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 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
529 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
531 s->lasttimeout = whennext;
537 static int ast_readvideo_callback(void *data)
539 struct ast_filestream *s = data;
540 struct ast_frame *fr;
544 fr = s->fmt->read(s, &whennext);
546 if (ast_write(s->owner, fr)) {
547 ast_log(LOG_WARNING, "Failed to write frame\n");
548 s->owner->vstreamid = -1;
552 /* Stream has finished */
553 s->owner->vstreamid = -1;
557 if (whennext != s->lasttimeout) {
558 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
559 s->lasttimeout = whennext;
565 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
571 int ast_playstream(struct ast_filestream *s)
573 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
574 ast_readaudio_callback(s);
576 ast_readvideo_callback(s);
580 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
582 return fs->fmt->seek(fs, sample_offset, whence);
585 int ast_truncstream(struct ast_filestream *fs)
587 return fs->fmt->trunc(fs);
590 long ast_tellstream(struct ast_filestream *fs)
592 return fs->fmt->tell(fs);
595 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
597 /* I think this is right, 8000 samples per second, 1000 ms a second so 8
599 long samples = ms * 8;
600 return ast_seekstream(fs, samples, SEEK_CUR);
603 int ast_stream_rewind(struct ast_filestream *fs, long ms)
605 long samples = ms * 8;
606 samples = samples * -1;
607 return ast_seekstream(fs, samples, SEEK_CUR);
610 int ast_closestream(struct ast_filestream *f)
612 /* Stop a running stream if there is one */
614 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
615 f->owner->stream = NULL;
616 if (f->owner->streamid > -1)
617 ast_sched_del(f->owner->sched, f->owner->streamid);
618 f->owner->streamid = -1;
619 #ifdef ZAPTEL_OPTIMIZATIONS
620 ast_settimeout(f->owner, 0, NULL, NULL);
623 f->owner->vstream = NULL;
624 if (f->owner->vstreamid > -1)
625 ast_sched_del(f->owner->sched, f->owner->vstreamid);
626 f->owner->vstreamid = -1;
637 int ast_fileexists(char *filename, char *fmt, char *preflang)
644 char lang2[MAX_LANGUAGE];
646 if (preflang && strlen(preflang)) {
647 /* Insert the language between the last two parts of the path */
648 strncpy(tmp, filename, sizeof(tmp) - 1);
649 c = strrchr(tmp, '/');
658 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
659 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
662 strncpy(lang2, preflang, sizeof(lang2)-1);
664 strsep(&stringp, "_");
665 if (strcmp(lang2, preflang)) {
666 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
667 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
672 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
677 int ast_filedelete(char *filename, char *fmt)
679 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
682 int ast_filerename(char *filename, char *filename2, char *fmt)
684 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
687 int ast_filecopy(char *filename, char *filename2, char *fmt)
689 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
692 int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
694 struct ast_filestream *fs;
695 struct ast_filestream *vfs;
697 fs = ast_openstream(chan, filename, preflang);
698 vfs = ast_openvstream(chan, filename, preflang);
700 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
702 ast_log(LOG_DEBUG, "Waaah, '%s' has no video stream :(\n", filename);
704 if(ast_applystream(chan, fs))
706 if(vfs && ast_applystream(chan, vfs))
708 if(ast_playstream(fs))
710 if(vfs && ast_playstream(vfs))
713 if (option_verbose > 2)
714 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s'\n", filename);
718 ast_log(LOG_WARNING, "Unable to open %s (format %d): %s\n", filename, chan->nativeformats, strerror(errno));
723 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
726 struct ast_format *f;
727 struct ast_filestream *fs=NULL;
730 if (ast_pthread_mutex_lock(&formatlock)) {
731 ast_log(LOG_WARNING, "Unable to lock format list\n");
735 /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
736 if (!(flags & O_APPEND)) myflags = O_TRUNC;
739 if (!strcasecmp(f->name, type)) {
741 /* XXX Implement check XXX */
742 ext = strdup(f->exts);
744 ext = strsep(&stringp, "|");
745 fn = build_filename(filename, ext);
746 fd = open(fn, flags | myflags | O_WRONLY | O_CREAT, mode);
749 if ((fs = f->rewrite(fd, comment))) {
754 fs->filename = strdup(filename);
757 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
761 } else if (errno != EEXIST)
762 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
769 ast_pthread_mutex_unlock(&formatlock);
771 ast_log(LOG_WARNING, "No such format '%s'\n", type);
775 char ast_waitstream(struct ast_channel *c, char *breakon)
777 /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
779 struct ast_frame *fr;
781 res = ast_sched_wait(c->sched);
782 if ((res < 0) && !c->timingfunc) {
784 ast_closestream(c->stream);
786 ast_closestream(c->vstream);
791 res = ast_waitfor(c, res);
793 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
795 } else if (res > 0) {
799 ast_log(LOG_DEBUG, "Got hung up\n");
804 switch(fr->frametype) {
807 if (strchr(breakon, res)) {
812 case AST_FRAME_CONTROL:
813 switch(fr->subclass) {
814 case AST_CONTROL_HANGUP:
817 case AST_CONTROL_RINGING:
818 case AST_CONTROL_ANSWER:
822 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
828 ast_sched_runq(c->sched);
830 return (c->_softhangup ? -1 : 0);
833 char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
836 struct ast_frame *fr;
838 res = ast_sched_wait(c->sched);
839 if ((res < 0) && !c->timingfunc) {
841 ast_closestream(c->stream);
843 ast_closestream(c->vstream);
848 res = ast_waitfor(c, res);
850 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
857 ast_log(LOG_DEBUG, "Got hung up\n");
862 switch(fr->frametype) {
865 if (strchr(forward,res)) {
866 ast_stream_fastforward(c->stream, ms);
867 } else if (strchr(rewind,res)) {
868 ast_stream_rewind(c->stream, ms);
869 } else if (strchr(breakon, res)) {
874 case AST_FRAME_CONTROL:
875 switch(fr->subclass) {
876 case AST_CONTROL_HANGUP:
879 case AST_CONTROL_RINGING:
880 case AST_CONTROL_ANSWER:
884 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
890 ast_sched_runq(c->sched);
894 return (c->_softhangup ? -1 : 0);
897 char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
902 struct ast_frame *fr;
903 struct ast_channel *rchan;
906 ms = ast_sched_wait(c->sched);
907 if ((ms < 0) && !c->timingfunc) {
909 ast_closestream(c->stream);
911 ast_closestream(c->vstream);
916 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
917 if (!rchan && (outfd < 0) && (ms)) {
918 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
920 } else if (outfd > -1) {
921 /* The FD we were watching has something waiting */
927 ast_log(LOG_DEBUG, "Got hung up\n");
932 switch(fr->frametype) {
935 if (strchr(breakon, res)) {
940 case AST_FRAME_CONTROL:
941 switch(fr->subclass) {
942 case AST_CONTROL_HANGUP:
945 case AST_CONTROL_RINGING:
946 case AST_CONTROL_ANSWER:
950 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
952 case AST_FRAME_VOICE:
953 /* Write audio if appropriate */
955 write(audiofd, fr->data, fr->datalen);
960 ast_sched_runq(c->sched);
964 return (c->_softhangup ? -1 : 0);