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>
15 #include <asterisk/frame.h>
16 #include <asterisk/file.h>
17 #include <asterisk/cli.h>
18 #include <asterisk/logger.h>
19 #include <asterisk/channel.h>
20 #include <asterisk/sched.h>
21 #include <asterisk/options.h>
22 #include <asterisk/translate.h>
23 #include <asterisk/utils.h>
24 #include <asterisk/lock.h>
25 #include <asterisk/app.h>
33 #include <sys/types.h>
41 /* Extensions (separated by | if more than one)
42 this format can read. First is assumed for writing (e.g. .mp3) */
44 /* Format of frames it uses/provides (one only) */
46 /* Open an input stream, and start playback */
47 struct ast_filestream * (*open)(int fd);
48 /* Open an output stream, of a given file descriptor and comment it appropriately if applicable */
49 struct ast_filestream * (*rewrite)(int fd, const char *comment);
50 /* Write a frame to a channel */
51 int (*write)(struct ast_filestream *, struct ast_frame *);
52 /* seek num samples into file, whence(think normal seek) */
53 int (*seek)(struct ast_filestream *, long offset, int whence);
54 /* trunc file to current position */
55 int (*trunc)(struct ast_filestream *fs);
56 /* tell current position */
57 long (*tell)(struct ast_filestream *fs);
58 /* Read the next frame from the filestream (if available) and report when to get next one
60 struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
61 /* Close file, and destroy filestream structure */
62 void (*close)(struct ast_filestream *);
63 /* Retrieve file comment */
64 char * (*getcomment)(struct ast_filestream *);
66 struct ast_format *next;
69 struct ast_filestream {
70 /* Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
71 struct ast_format *fmt;
76 /* Video file stream */
77 struct ast_filestream *vfs;
78 /* Transparently translate from another format -- just once */
79 struct ast_trans_pvt *trans;
80 struct ast_tranlator_pvt *tr;
83 struct ast_channel *owner;
86 AST_MUTEX_DEFINE_STATIC(formatlock);
88 static struct ast_format *formats = NULL;
90 int ast_format_register(const char *name, const char *exts, int format,
91 struct ast_filestream * (*open)(int fd),
92 struct ast_filestream * (*rewrite)(int fd, const char *comment),
93 int (*write)(struct ast_filestream *, struct ast_frame *),
94 int (*seek)(struct ast_filestream *, long sample_offset, int whence),
95 int (*trunc)(struct ast_filestream *),
96 long (*tell)(struct ast_filestream *),
97 struct ast_frame * (*read)(struct ast_filestream *, int *whennext),
98 void (*close)(struct ast_filestream *),
99 char * (*getcomment)(struct ast_filestream *))
101 struct ast_format *tmp;
102 if (ast_mutex_lock(&formatlock)) {
103 ast_log(LOG_WARNING, "Unable to lock format list\n");
108 if (!strcasecmp(name, tmp->name)) {
109 ast_mutex_unlock(&formatlock);
110 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
115 tmp = malloc(sizeof(struct ast_format));
117 ast_log(LOG_WARNING, "Out of memory\n");
118 ast_mutex_unlock(&formatlock);
121 strncpy(tmp->name, name, sizeof(tmp->name)-1);
122 strncpy(tmp->exts, exts, sizeof(tmp->exts)-1);
124 tmp->rewrite = rewrite;
131 tmp->format = format;
132 tmp->getcomment = getcomment;
135 ast_mutex_unlock(&formatlock);
136 if (option_verbose > 1)
137 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
141 int ast_format_unregister(const char *name)
143 struct ast_format *tmp, *tmpl = NULL;
144 if (ast_mutex_lock(&formatlock)) {
145 ast_log(LOG_WARNING, "Unable to lock format list\n");
150 if (!strcasecmp(name, tmp->name)) {
152 tmpl->next = tmp->next;
156 ast_mutex_unlock(&formatlock);
157 if (option_verbose > 1)
158 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
164 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
168 int ast_stopstream(struct ast_channel *tmp)
170 /* Stop a running stream if there is one */
172 ast_closestream(tmp->vstream);
174 ast_closestream(tmp->stream);
175 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
176 ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
181 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
183 struct ast_frame *trf;
186 if (f->frametype == AST_FRAME_VIDEO) {
187 if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
188 /* This is the audio portion. Call the video one... */
189 if (!fs->vfs && fs->filename) {
190 /* XXX Support other video formats XXX */
191 const char *type = "h263";
192 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
193 ast_log(LOG_DEBUG, "Opened video output file\n");
196 return ast_writestream(fs->vfs, f);
200 /* Might / might not have mark set */
203 } else if (f->frametype != AST_FRAME_VOICE) {
204 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
207 if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
208 res = fs->fmt->write(fs, f);
210 ast_log(LOG_WARNING, "Natural write failed\n");
212 ast_log(LOG_WARNING, "Huh??\n");
215 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
216 the one we've setup a translator for, we do the "wrong thing" XXX */
217 if (fs->trans && (f->subclass != fs->lastwriteformat)) {
218 ast_translator_free_path(fs->trans);
222 fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
224 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n", fs->fmt->name, ast_getformatname(f->subclass));
226 fs->lastwriteformat = f->subclass;
228 /* Get the translated frame but don't consume the original in case they're using it on another stream */
229 trf = ast_translate(fs->trans, f, 0);
231 res = fs->fmt->write(fs, trf);
233 ast_log(LOG_WARNING, "Translated frame write failed\n");
241 static int copy(const char *infile, const char *outfile)
249 if ((ifd = open(infile, O_RDONLY)) < 0) {
250 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
253 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
254 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
259 len = read(ifd, buf, sizeof(buf));
261 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
267 res = write(ofd, buf, len);
269 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
281 static char *build_filename(const const char *filename, const char *ext)
285 char tmp[AST_CONFIG_MAX_PATH]="";
287 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_VAR_DIR, "sounds");
288 fnsize = strlen(tmp) + strlen(filename) + strlen(ext) + 10;
291 if (filename[0] == '/')
292 snprintf(fn, fnsize, "%s.%s", filename, ext);
294 snprintf(fn, fnsize, "%s/%s.%s", tmp, filename, ext);
300 static int exts_compare(const char *exts, const const char *type)
302 char *stringp = NULL, *ext;
305 strncpy(tmp, exts, sizeof(tmp) - 1);
307 while ((ext = strsep(&stringp, "|"))) {
308 if (!strcmp(ext, type)) {
316 #define ACTION_EXISTS 1
317 #define ACTION_DELETE 2
318 #define ACTION_RENAME 3
319 #define ACTION_OPEN 4
320 #define ACTION_COPY 5
322 static int ast_filehelper(const char *filename, const char *filename2, const char *fmt, int action)
325 struct ast_format *f;
326 struct ast_filestream *s;
328 char *ext=NULL, *exts, *fn, *nfn;
329 struct ast_channel *chan = (struct ast_channel *)filename2;
331 /* Start with negative response */
332 if (action == ACTION_EXISTS)
336 if (action == ACTION_OPEN)
338 /* Check for a specific format */
339 if (ast_mutex_lock(&formatlock)) {
340 ast_log(LOG_WARNING, "Unable to lock format list\n");
341 if (action == ACTION_EXISTS)
348 if (!fmt || exts_compare(f->exts, fmt)) {
350 exts = strdup(f->exts);
351 /* Try each kind of extension */
353 ext = strsep(&stringp, "|");
354 if (!strcmp(ext,"wav49")) {
358 fn = build_filename(filename, ext);
369 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
372 nfn = build_filename(filename2, ext);
374 res = rename(fn, nfn);
376 ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
379 ast_log(LOG_WARNING, "Out of memory\n");
382 nfn = build_filename(filename2, ext);
386 ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
389 ast_log(LOG_WARNING, "Out of memory\n");
392 if ((ret < 0) && ((chan->writeformat & f->format) ||
393 ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
394 ret = open(fn, O_RDONLY);
402 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
408 ast_log(LOG_WARNING, "Unable to open fd on %s\n", fn);
411 ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
415 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
417 /* Conveniently this logic is the same for all */
423 ext = strsep(&stringp, "|");
429 ast_mutex_unlock(&formatlock);
430 if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
431 res = ret ? ret : -1;
435 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
437 /* This is a fairly complex routine. Essentially we should do
440 1) Find which file handlers produce our type of format.
441 2) Look for a filename which it can handle.
442 3) If we find one, then great.
443 4) If not, see what files are there
444 5) See what we can actually support
445 6) Choose the one with the least costly translator path and
451 char filename2[256]="";
452 char filename3[256]="";
455 ast_stopstream(chan);
456 /* do this first, otherwise we detect the wrong writeformat */
458 ast_deactivate_generator(chan);
459 if (preflang && !ast_strlen_zero(preflang)) {
460 strncpy(filename3, filename, sizeof(filename3) - 1);
461 endpart = strrchr(filename3, '/');
465 snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
467 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
468 fmts = ast_fileexists(filename2, NULL, NULL);
471 strncpy(filename2, filename, sizeof(filename2)-1);
472 fmts = ast_fileexists(filename2, NULL, NULL);
475 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
478 chan->oldwriteformat = chan->writeformat;
479 /* Set the channel to a format we can work with */
480 res = ast_set_write_format(chan, fmts);
482 fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
488 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
490 /* This is a fairly complex routine. Essentially we should do
493 1) Find which file handlers produce our type of format.
494 2) Look for a filename which it can handle.
495 3) If we find one, then great.
496 4) If not, see what files are there
497 5) See what we can actually support
498 6) Choose the one with the least costly translator path and
505 char lang2[MAX_LANGUAGE];
506 /* XXX H.263 only XXX */
508 if (preflang && !ast_strlen_zero(preflang)) {
509 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
510 fmts = ast_fileexists(filename2, fmt, NULL);
512 strncpy(lang2, preflang, sizeof(lang2)-1);
513 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
514 fmts = ast_fileexists(filename2, fmt, NULL);
518 strncpy(filename2, filename, sizeof(filename2)-1);
519 fmts = ast_fileexists(filename2, fmt, NULL);
524 fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
526 return chan->vstream;
527 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
531 struct ast_frame *ast_readframe(struct ast_filestream *s)
533 struct ast_frame *f = NULL;
536 f = s->fmt->read(s, &whennext);
540 static int ast_readaudio_callback(void *data)
542 struct ast_filestream *s = data;
543 struct ast_frame *fr;
547 fr = s->fmt->read(s, &whennext);
549 if (ast_write(s->owner, fr)) {
550 ast_log(LOG_WARNING, "Failed to write frame\n");
551 s->owner->streamid = -1;
552 #ifdef ZAPTEL_OPTIMIZATIONS
553 ast_settimeout(s->owner, 0, NULL, NULL);
558 /* Stream has finished */
559 s->owner->streamid = -1;
560 #ifdef ZAPTEL_OPTIMIZATIONS
561 ast_settimeout(s->owner, 0, NULL, NULL);
566 if (whennext != s->lasttimeout) {
567 #ifdef ZAPTEL_OPTIMIZATIONS
568 if (s->owner->timingfd > -1)
569 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
572 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
573 s->lasttimeout = whennext;
579 static int ast_readvideo_callback(void *data)
581 struct ast_filestream *s = data;
582 struct ast_frame *fr;
586 fr = s->fmt->read(s, &whennext);
588 if (ast_write(s->owner, fr)) {
589 ast_log(LOG_WARNING, "Failed to write frame\n");
590 s->owner->vstreamid = -1;
594 /* Stream has finished */
595 s->owner->vstreamid = -1;
599 if (whennext != s->lasttimeout) {
600 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
601 s->lasttimeout = whennext;
607 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
613 int ast_playstream(struct ast_filestream *s)
615 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
616 ast_readaudio_callback(s);
618 ast_readvideo_callback(s);
622 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
624 return fs->fmt->seek(fs, sample_offset, whence);
627 int ast_truncstream(struct ast_filestream *fs)
629 return fs->fmt->trunc(fs);
632 long ast_tellstream(struct ast_filestream *fs)
634 return fs->fmt->tell(fs);
637 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
639 /* I think this is right, 8000 samples per second, 1000 ms a second so 8
641 long samples = ms * 8;
642 return ast_seekstream(fs, samples, SEEK_CUR);
645 int ast_stream_rewind(struct ast_filestream *fs, long ms)
647 long samples = ms * 8;
648 samples = samples * -1;
649 return ast_seekstream(fs, samples, SEEK_CUR);
652 int ast_closestream(struct ast_filestream *f)
656 /* Stop a running stream if there is one */
658 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
659 f->owner->stream = NULL;
660 if (f->owner->streamid > -1)
661 ast_sched_del(f->owner->sched, f->owner->streamid);
662 f->owner->streamid = -1;
663 #ifdef ZAPTEL_OPTIMIZATIONS
664 ast_settimeout(f->owner, 0, NULL, NULL);
667 f->owner->vstream = NULL;
668 if (f->owner->vstreamid > -1)
669 ast_sched_del(f->owner->sched, f->owner->vstreamid);
670 f->owner->vstreamid = -1;
673 /* destroy the translator on exit */
675 ast_translator_free_path(f->trans);
679 if (f->realfilename && f->filename) {
680 size = strlen(f->filename) + strlen(f->realfilename) + 15;
683 snprintf(cmd,size,"/bin/mv -f %s %s",f->filename,f->realfilename);
684 ast_safe_system(cmd);
691 if (f->realfilename) {
692 free(f->realfilename);
693 f->realfilename = NULL;
700 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
707 char lang2[MAX_LANGUAGE];
709 if (preflang && !ast_strlen_zero(preflang)) {
710 /* Insert the language between the last two parts of the path */
711 strncpy(tmp, filename, sizeof(tmp) - 1);
712 c = strrchr(tmp, '/');
721 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
722 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
725 strncpy(lang2, preflang, sizeof(lang2)-1);
727 strsep(&stringp, "_");
728 if (strcmp(lang2, preflang)) {
729 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
730 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
735 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
740 int ast_filedelete(const char *filename, const char *fmt)
742 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
745 int ast_filerename(const char *filename, const char *filename2, const char *fmt)
747 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
750 int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
752 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
755 int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
757 struct ast_filestream *fs;
758 struct ast_filestream *vfs;
760 fs = ast_openstream(chan, filename, preflang);
761 vfs = ast_openvstream(chan, filename, preflang);
763 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
765 if (ast_applystream(chan, fs))
767 if (vfs && ast_applystream(chan, vfs))
769 if (ast_playstream(fs))
771 if (vfs && ast_playstream(vfs))
774 if (option_verbose > 2)
775 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
779 ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
783 struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
786 struct ast_format *f;
787 struct ast_filestream *fs=NULL;
790 if (ast_mutex_lock(&formatlock)) {
791 ast_log(LOG_WARNING, "Unable to lock format list\n");
796 if (exts_compare(f->exts, type)) {
798 /* XXX Implement check XXX */
799 ext = strdup(f->exts);
801 ext = strsep(&stringp, "|");
802 fn = build_filename(filename, ext);
803 fd = open(fn, flags | myflags);
806 if ((fs = f->open(fd))) {
811 fs->filename = strdup(filename);
814 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
818 } else if (errno != EEXIST)
819 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
826 ast_mutex_unlock(&formatlock);
828 ast_log(LOG_WARNING, "No such format '%s'\n", type);
832 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
835 struct ast_format *f;
836 struct ast_filestream *fs=NULL;
837 char *fn,*orig_fn=NULL;
842 if (ast_mutex_lock(&formatlock)) {
843 ast_log(LOG_WARNING, "Unable to lock format list\n");
846 /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
847 if (!(flags & O_APPEND))
850 myflags |= O_WRONLY | O_CREAT;
854 if (exts_compare(f->exts, type)) {
856 /* XXX Implement check XXX */
857 ext = ast_strdupa(f->exts);
859 ext = strsep(&stringp, "|");
860 fn = build_filename(filename, ext);
861 fd = open(fn, flags | myflags, mode);
863 if (option_cache_record_files && fd >= 0) {
866 We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
867 What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
869 orig_fn = ast_strdupa(fn);
870 for (size=0;size<strlen(fn);size++) {
875 size += (strlen(record_cache_dir) + 10);
877 memset(buf, 0, size);
878 snprintf(buf, size, "%s/%s", record_cache_dir, fn);
881 fd = open(fn, flags | myflags, mode);
885 if ((fs = f->rewrite(fd, comment))) {
890 if (option_cache_record_files) {
891 fs->realfilename = build_filename(filename, ext);
892 fs->filename = strdup(fn);
894 fs->realfilename = NULL;
895 fs->filename = strdup(filename);
899 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
905 } else if (errno != EEXIST) {
906 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
910 if (!buf) /* if buf != NULL then fn is already free and pointing to it */
917 ast_mutex_unlock(&formatlock);
919 ast_log(LOG_WARNING, "No such format '%s'\n", type);
923 char ast_waitstream(struct ast_channel *c, const char *breakon)
925 /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
927 struct ast_frame *fr;
928 if (!breakon) breakon = "";
930 res = ast_sched_wait(c->sched);
931 if ((res < 0) && !c->timingfunc) {
937 res = ast_waitfor(c, res);
939 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
941 } else if (res > 0) {
945 ast_log(LOG_DEBUG, "Got hung up\n");
950 switch(fr->frametype) {
953 if (strchr(breakon, res)) {
958 case AST_FRAME_CONTROL:
959 switch(fr->subclass) {
960 case AST_CONTROL_HANGUP:
963 case AST_CONTROL_RINGING:
964 case AST_CONTROL_ANSWER:
968 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
974 ast_sched_runq(c->sched);
976 return (c->_softhangup ? -1 : 0);
979 char ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
982 struct ast_frame *fr;
984 res = ast_sched_wait(c->sched);
985 if ((res < 0) && !c->timingfunc) {
991 res = ast_waitfor(c, res);
993 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1000 ast_log(LOG_DEBUG, "Got hung up\n");
1005 switch(fr->frametype) {
1006 case AST_FRAME_DTMF:
1008 if (strchr(forward,res)) {
1009 ast_stream_fastforward(c->stream, ms);
1010 } else if (strchr(rewind,res)) {
1011 ast_stream_rewind(c->stream, ms);
1012 } else if (strchr(breakon, res)) {
1017 case AST_FRAME_CONTROL:
1018 switch(fr->subclass) {
1019 case AST_CONTROL_HANGUP:
1022 case AST_CONTROL_RINGING:
1023 case AST_CONTROL_ANSWER:
1027 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1033 ast_sched_runq(c->sched);
1037 return (c->_softhangup ? -1 : 0);
1040 char ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1045 struct ast_frame *fr;
1046 struct ast_channel *rchan;
1049 ms = ast_sched_wait(c->sched);
1050 if ((ms < 0) && !c->timingfunc) {
1056 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1057 if (!rchan && (outfd < 0) && (ms)) {
1058 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1060 } else if (outfd > -1) {
1061 /* The FD we were watching has something waiting */
1067 ast_log(LOG_DEBUG, "Got hung up\n");
1072 switch(fr->frametype) {
1073 case AST_FRAME_DTMF:
1075 if (strchr(breakon, res)) {
1080 case AST_FRAME_CONTROL:
1081 switch(fr->subclass) {
1082 case AST_CONTROL_HANGUP:
1085 case AST_CONTROL_RINGING:
1086 case AST_CONTROL_ANSWER:
1090 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1092 case AST_FRAME_VOICE:
1093 /* Write audio if appropriate */
1095 write(audiofd, fr->data, fr->datalen);
1100 ast_sched_runq(c->sched);
1104 return (c->_softhangup ? -1 : 0);
1107 static int show_file_formats(int fd, int argc, char *argv[])
1109 #define FORMAT "%-10s %-10s %-20s\n"
1110 #define FORMAT2 "%-10s %-10s %-20s\n"
1111 struct ast_format *f;
1113 return RESULT_SHOWUSAGE;
1114 ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
1116 if (ast_mutex_lock(&formatlock)) {
1117 ast_log(LOG_WARNING, "Unable to lock format list\n");
1123 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1126 ast_mutex_unlock(&formatlock);
1127 return RESULT_SUCCESS;
1130 struct ast_cli_entry show_file =
1132 { "show", "file", "formats" },
1134 "Displays file formats",
1135 "Usage: show file formats\n"
1136 " displays currently registered file formats (if any)\n"
1139 int ast_file_init(void)
1141 ast_cli_register(&show_file);