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/logger.h>
18 #include <asterisk/channel.h>
19 #include <asterisk/sched.h>
20 #include <asterisk/options.h>
21 #include <asterisk/translate.h>
37 /* Extensions (separated by | if more than one)
38 this format can read. First is assumed for writing (e.g. .mp3) */
40 /* Format of frames it uses/provides (one only) */
42 /* Open an input stream, and start playback */
43 struct ast_filestream * (*open)(int fd);
44 /* Open an output stream, of a given file descriptor and comment it appropriately if applicable */
45 struct ast_filestream * (*rewrite)(int fd, char *comment);
46 /* Write a frame to a channel */
47 int (*write)(struct ast_filestream *, struct ast_frame *);
48 /* seek num samples into file, whence(think normal seek) */
49 int (*seek)(struct ast_filestream *, long offset, int whence);
50 /* trunc file to current position */
51 int (*trunc)(struct ast_filestream *fs);
52 /* tell current position */
53 long (*tell)(struct ast_filestream *fs);
54 /* Read the next frame from the filestream (if available) and report when to get next one
56 struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
57 /* Close file, and destroy filestream structure */
58 void (*close)(struct ast_filestream *);
59 /* Retrieve file comment */
60 char * (*getcomment)(struct ast_filestream *);
62 struct ast_format *next;
65 struct ast_filestream {
66 /* Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
67 struct ast_format *fmt;
71 /* Video file stream */
72 struct ast_filestream *vfs;
73 /* Transparently translate from another format -- just once */
74 struct ast_trans_pvt *trans;
75 struct ast_tranlator_pvt *tr;
78 struct ast_channel *owner;
81 static pthread_mutex_t formatlock = AST_MUTEX_INITIALIZER;
83 static struct ast_format *formats = NULL;
85 int ast_format_register(char *name, char *exts, int format,
86 struct ast_filestream * (*open)(int fd),
87 struct ast_filestream * (*rewrite)(int fd, char *comment),
88 int (*write)(struct ast_filestream *, struct ast_frame *),
89 int (*seek)(struct ast_filestream *, long sample_offset, int whence),
90 int (*trunc)(struct ast_filestream *),
91 long (*tell)(struct ast_filestream *),
92 struct ast_frame * (*read)(struct ast_filestream *, int *whennext),
93 void (*close)(struct ast_filestream *),
94 char * (*getcomment)(struct ast_filestream *))
96 struct ast_format *tmp;
97 if (ast_pthread_mutex_lock(&formatlock)) {
98 ast_log(LOG_WARNING, "Unable to lock format list\n");
103 if (!strcasecmp(name, tmp->name)) {
104 ast_pthread_mutex_unlock(&formatlock);
105 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
110 tmp = malloc(sizeof(struct ast_format));
112 ast_log(LOG_WARNING, "Out of memory\n");
113 ast_pthread_mutex_unlock(&formatlock);
116 strncpy(tmp->name, name, sizeof(tmp->name)-1);
117 strncpy(tmp->exts, exts, sizeof(tmp->exts)-1);
119 tmp->rewrite = rewrite;
126 tmp->format = format;
127 tmp->getcomment = getcomment;
130 ast_pthread_mutex_unlock(&formatlock);
131 if (option_verbose > 1)
132 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
136 int ast_format_unregister(char *name)
138 struct ast_format *tmp, *tmpl = NULL;
139 if (ast_pthread_mutex_lock(&formatlock)) {
140 ast_log(LOG_WARNING, "Unable to lock format list\n");
145 if (!strcasecmp(name, tmp->name)) {
147 tmpl->next = tmp->next;
151 ast_pthread_mutex_unlock(&formatlock);
152 if (option_verbose > 1)
153 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
158 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
162 int ast_stopstream(struct ast_channel *tmp)
164 /* Stop a running stream if there is one */
166 ast_closestream(tmp->vstream);
168 ast_closestream(tmp->stream);
169 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
170 ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
175 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
177 struct ast_frame *trf;
180 if (f->frametype == AST_FRAME_VIDEO) {
181 if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
182 /* This is the audio portion. Call the video one... */
183 if (!fs->vfs && fs->filename) {
184 /* XXX Support other video formats XXX */
186 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
187 ast_log(LOG_DEBUG, "Opened video output file\n");
190 return ast_writestream(fs->vfs, f);
194 /* Might / might not have mark set */
197 } else if (f->frametype != AST_FRAME_VOICE) {
198 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
201 if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
202 res = fs->fmt->write(fs, f);
204 ast_log(LOG_WARNING, "Natural write failed\n");
206 ast_log(LOG_WARNING, "Huh??\n");
209 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
210 the one we've setup a translator for, we do the "wrong thing" XXX */
211 if (fs->trans && (f->subclass != fs->lastwriteformat)) {
212 ast_translator_free_path(fs->trans);
216 fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
218 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %d\n", fs->fmt->name, f->subclass);
220 fs->lastwriteformat = f->subclass;
222 /* Get the translated frame but don't consume the original in case they're using it on another stream */
223 trf = ast_translate(fs->trans, f, 0);
225 res = fs->fmt->write(fs, trf);
227 ast_log(LOG_WARNING, "Translated frame write failed\n");
235 static int copy(char *infile, char *outfile)
242 if ((ifd = open(infile, O_RDONLY)) < 0) {
243 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
246 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
247 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
252 len = read(ifd, buf, sizeof(buf));
254 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
260 res = write(ofd, buf, len);
262 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
274 static char *build_filename(char *filename, char *ext)
277 char tmp[AST_CONFIG_MAX_PATH];
278 snprintf(tmp,sizeof(tmp)-1,"%s/%s",(char *)ast_config_AST_VAR_DIR,"sounds");
279 fn = malloc(strlen(tmp) + strlen(filename) + strlen(ext) + 10);
281 if (filename[0] == '/')
282 sprintf(fn, "%s.%s", filename, ext);
284 sprintf(fn, "%s/%s.%s", (char *)tmp, filename, ext);
290 #define ACTION_EXISTS 1
291 #define ACTION_DELETE 2
292 #define ACTION_RENAME 3
293 #define ACTION_OPEN 4
294 #define ACTION_COPY 5
296 static int ast_filehelper(char *filename, char *filename2, char *fmt, int action)
299 struct ast_format *f;
300 struct ast_filestream *s;
302 char *ext=NULL, *exts, *fn, *nfn;
303 struct ast_channel *chan = (struct ast_channel *)filename2;
305 /* Start with negative response */
306 if (action == ACTION_EXISTS)
310 if (action == ACTION_OPEN)
312 /* Check for a specific format */
313 if (ast_pthread_mutex_lock(&formatlock)) {
314 ast_log(LOG_WARNING, "Unable to lock format list\n");
315 if (action == ACTION_EXISTS)
322 if (!fmt || !strcasecmp(f->name, fmt)) {
324 exts = strdup(f->exts);
325 /* Try each kind of extension */
327 ext = strsep(&stringp, "|");
329 fn = build_filename(filename, ext);
340 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
343 nfn = build_filename(filename2, ext);
345 res = rename(fn, nfn);
347 ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
350 ast_log(LOG_WARNING, "Out of memory\n");
353 nfn = build_filename(filename2, ext);
357 ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
360 ast_log(LOG_WARNING, "Out of memory\n");
363 if ((ret < 0) && ((chan->writeformat & f->format) ||
364 ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
365 ret = open(fn, O_RDONLY);
373 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
379 ast_log(LOG_WARNING, "Unable to open fd on %s\n", filename);
382 ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
386 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
388 /* Conveniently this logic is the same for all */
394 ext = strsep(&stringp, "|");
400 ast_pthread_mutex_unlock(&formatlock);
401 if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
402 res = ret ? ret : -1;
406 struct ast_filestream *ast_openstream(struct ast_channel *chan, char *filename, char *preflang)
408 /* This is a fairly complex routine. Essentially we should do
411 1) Find which file handlers produce our type of format.
412 2) Look for a filename which it can handle.
413 3) If we find one, then great.
414 4) If not, see what files are there
415 5) See what we can actually support
416 6) Choose the one with the least costly translator path and
423 char lang2[MAX_LANGUAGE];
425 ast_stopstream(chan);
426 /* do this first, otherwise we detect the wrong writeformat */
428 ast_deactivate_generator(chan);
429 if (preflang && strlen(preflang)) {
430 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
431 fmts = ast_fileexists(filename2, NULL, NULL);
433 strncpy(lang2, preflang, sizeof(lang2)-1);
434 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
435 fmts = ast_fileexists(filename2, NULL, NULL);
439 strncpy(filename2, filename, sizeof(filename2)-1);
440 fmts = ast_fileexists(filename2, NULL, NULL);
443 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
446 chan->oldwriteformat = chan->writeformat;
447 /* Set the channel to a format we can work with */
448 res = ast_set_write_format(chan, fmts);
450 fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
456 struct ast_filestream *ast_openvstream(struct ast_channel *chan, char *filename, char *preflang)
458 /* This is a fairly complex routine. Essentially we should do
461 1) Find which file handlers produce our type of format.
462 2) Look for a filename which it can handle.
463 3) If we find one, then great.
464 4) If not, see what files are there
465 5) See what we can actually support
466 6) Choose the one with the least costly translator path and
473 char lang2[MAX_LANGUAGE];
474 /* XXX H.263 only XXX */
476 if (preflang && strlen(preflang)) {
477 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
478 fmts = ast_fileexists(filename2, fmt, NULL);
480 strncpy(lang2, preflang, sizeof(lang2)-1);
481 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
482 fmts = ast_fileexists(filename2, fmt, NULL);
486 strncpy(filename2, filename, sizeof(filename2)-1);
487 fmts = ast_fileexists(filename2, fmt, NULL);
492 fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
494 return chan->vstream;
495 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
499 static int ast_readaudio_callback(void *data)
501 struct ast_filestream *s = data;
502 struct ast_frame *fr;
506 fr = s->fmt->read(s, &whennext);
508 if (ast_write(s->owner, fr)) {
509 ast_log(LOG_WARNING, "Failed to write frame\n");
510 s->owner->streamid = -1;
511 #ifdef ZAPTEL_OPTIMIZATIONS
512 ast_settimeout(s->owner, 0, NULL, NULL);
517 /* Stream has finished */
518 s->owner->streamid = -1;
519 #ifdef ZAPTEL_OPTIMIZATIONS
520 ast_settimeout(s->owner, 0, NULL, NULL);
525 if (whennext != s->lasttimeout) {
526 #ifdef ZAPTEL_OPTIMIZATIONS
527 if (s->owner->timingfd > -1)
528 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
531 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
532 s->lasttimeout = whennext;
538 static int ast_readvideo_callback(void *data)
540 struct ast_filestream *s = data;
541 struct ast_frame *fr;
545 fr = s->fmt->read(s, &whennext);
547 if (ast_write(s->owner, fr)) {
548 ast_log(LOG_WARNING, "Failed to write frame\n");
549 s->owner->vstreamid = -1;
553 /* Stream has finished */
554 s->owner->vstreamid = -1;
558 if (whennext != s->lasttimeout) {
559 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
560 s->lasttimeout = whennext;
566 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
572 int ast_playstream(struct ast_filestream *s)
574 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
575 ast_readaudio_callback(s);
577 ast_readvideo_callback(s);
581 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
583 return fs->fmt->seek(fs, sample_offset, whence);
586 int ast_truncstream(struct ast_filestream *fs)
588 return fs->fmt->trunc(fs);
591 long ast_tellstream(struct ast_filestream *fs)
593 return fs->fmt->tell(fs);
596 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
598 /* I think this is right, 8000 samples per second, 1000 ms a second so 8
600 long samples = ms * 8;
601 return ast_seekstream(fs, samples, SEEK_CUR);
604 int ast_stream_rewind(struct ast_filestream *fs, long ms)
606 long samples = ms * 8;
607 samples = samples * -1;
608 return ast_seekstream(fs, samples, SEEK_CUR);
611 int ast_closestream(struct ast_filestream *f)
613 /* Stop a running stream if there is one */
615 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
616 f->owner->stream = NULL;
617 if (f->owner->streamid > -1)
618 ast_sched_del(f->owner->sched, f->owner->streamid);
619 f->owner->streamid = -1;
620 #ifdef ZAPTEL_OPTIMIZATIONS
621 ast_settimeout(f->owner, 0, NULL, NULL);
624 f->owner->vstream = NULL;
625 if (f->owner->vstreamid > -1)
626 ast_sched_del(f->owner->sched, f->owner->vstreamid);
627 f->owner->vstreamid = -1;
638 int ast_fileexists(char *filename, char *fmt, char *preflang)
645 char lang2[MAX_LANGUAGE];
647 if (preflang && strlen(preflang)) {
648 /* Insert the language between the last two parts of the path */
649 strncpy(tmp, filename, sizeof(tmp) - 1);
650 c = strrchr(tmp, '/');
659 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
660 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
663 strncpy(lang2, preflang, sizeof(lang2)-1);
665 strsep(&stringp, "_");
666 if (strcmp(lang2, preflang)) {
667 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
668 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
673 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
678 int ast_filedelete(char *filename, char *fmt)
680 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
683 int ast_filerename(char *filename, char *filename2, char *fmt)
685 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
688 int ast_filecopy(char *filename, char *filename2, char *fmt)
690 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
693 int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
695 struct ast_filestream *fs;
696 struct ast_filestream *vfs;
698 fs = ast_openstream(chan, filename, preflang);
699 vfs = ast_openvstream(chan, filename, preflang);
701 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
703 if(ast_applystream(chan, fs))
705 if(vfs && ast_applystream(chan, vfs))
707 if(ast_playstream(fs))
709 if(vfs && ast_playstream(vfs))
712 if (option_verbose > 2)
713 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s'\n", filename);
717 ast_log(LOG_WARNING, "Unable to open %s (format %d): %s\n", filename, chan->nativeformats, strerror(errno));
722 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
725 struct ast_format *f;
726 struct ast_filestream *fs=NULL;
729 if (ast_pthread_mutex_lock(&formatlock)) {
730 ast_log(LOG_WARNING, "Unable to lock format list\n");
734 /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
735 if (!(flags & O_APPEND)) myflags = O_TRUNC;
738 if (!strcasecmp(f->name, type)) {
740 /* XXX Implement check XXX */
741 ext = strdup(f->exts);
743 ext = strsep(&stringp, "|");
744 fn = build_filename(filename, ext);
745 fd = open(fn, flags | myflags | O_WRONLY | O_CREAT, mode);
748 if ((fs = f->rewrite(fd, comment))) {
753 fs->filename = strdup(filename);
756 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
760 } else if (errno != EEXIST)
761 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
768 ast_pthread_mutex_unlock(&formatlock);
770 ast_log(LOG_WARNING, "No such format '%s'\n", type);
774 char ast_waitstream(struct ast_channel *c, char *breakon)
776 /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
778 struct ast_frame *fr;
780 res = ast_sched_wait(c->sched);
781 if ((res < 0) && !c->timingfunc) {
787 res = ast_waitfor(c, res);
789 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
791 } else if (res > 0) {
795 ast_log(LOG_DEBUG, "Got hung up\n");
800 switch(fr->frametype) {
803 if (strchr(breakon, res)) {
808 case AST_FRAME_CONTROL:
809 switch(fr->subclass) {
810 case AST_CONTROL_HANGUP:
813 case AST_CONTROL_RINGING:
814 case AST_CONTROL_ANSWER:
818 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
824 ast_sched_runq(c->sched);
826 return (c->_softhangup ? -1 : 0);
829 char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
832 struct ast_frame *fr;
834 res = ast_sched_wait(c->sched);
835 if ((res < 0) && !c->timingfunc) {
841 res = ast_waitfor(c, res);
843 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
850 ast_log(LOG_DEBUG, "Got hung up\n");
855 switch(fr->frametype) {
858 if (strchr(forward,res)) {
859 ast_stream_fastforward(c->stream, ms);
860 } else if (strchr(rewind,res)) {
861 ast_stream_rewind(c->stream, ms);
862 } else if (strchr(breakon, res)) {
867 case AST_FRAME_CONTROL:
868 switch(fr->subclass) {
869 case AST_CONTROL_HANGUP:
872 case AST_CONTROL_RINGING:
873 case AST_CONTROL_ANSWER:
877 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
883 ast_sched_runq(c->sched);
887 return (c->_softhangup ? -1 : 0);
890 char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
895 struct ast_frame *fr;
896 struct ast_channel *rchan;
899 ms = ast_sched_wait(c->sched);
900 if ((ms < 0) && !c->timingfunc) {
906 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
907 if (!rchan && (outfd < 0) && (ms)) {
908 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
910 } else if (outfd > -1) {
911 /* The FD we were watching has something waiting */
917 ast_log(LOG_DEBUG, "Got hung up\n");
922 switch(fr->frametype) {
925 if (strchr(breakon, res)) {
930 case AST_FRAME_CONTROL:
931 switch(fr->subclass) {
932 case AST_CONTROL_HANGUP:
935 case AST_CONTROL_RINGING:
936 case AST_CONTROL_ANSWER:
940 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
942 case AST_FRAME_VOICE:
943 /* Write audio if appropriate */
945 write(audiofd, fr->data, fr->datalen);
950 ast_sched_runq(c->sched);
954 return (c->_softhangup ? -1 : 0);