2 * Asterisk -- A telephony toolkit for Linux.
4 * Generic File Format Support.
6 * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
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 <asterisk/frame.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/sched.h>
19 #include <asterisk/options.h>
20 #include <asterisk/translate.h>
35 /* Extensions (separated by | if more than one)
36 this format can read. First is assumed for writing (e.g. .mp3) */
38 /* Format of frames it uses/provides (one only) */
40 /* Open an input stream, and start playback */
41 struct ast_filestream * (*open)(int fd);
42 /* Open an output stream, of a given file descriptor and comment it appropriately if applicable */
43 struct ast_filestream * (*rewrite)(int fd, char *comment);
44 /* Apply a reading filestream to a channel */
45 int (*apply)(struct ast_channel *, struct ast_filestream *);
46 /* Write a frame to a channel */
47 int (*write)(struct ast_filestream *, struct ast_frame *);
48 /* Read the next frame from the filestream (if available) */
49 struct ast_frame * (*read)(struct ast_filestream *);
50 /* Close file, and destroy filestream structure */
51 void (*close)(struct ast_filestream *);
52 /* Retrieve file comment */
53 char * (*getcomment)(struct ast_filestream *);
55 struct ast_format *next;
58 struct ast_filestream {
59 /* Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
60 struct ast_format *fmt;
61 /* Transparently translate from another format -- just once */
62 struct ast_trans_pvt *trans;
63 struct ast_tranlator_pvt *tr;
66 static pthread_mutex_t formatlock = PTHREAD_MUTEX_INITIALIZER;
68 static struct ast_format *formats = NULL;
70 int ast_format_register(char *name, char *exts, int format,
71 struct ast_filestream * (*open)(int fd),
72 struct ast_filestream * (*rewrite)(int fd, char *comment),
73 int (*apply)(struct ast_channel *, struct ast_filestream *),
74 int (*write)(struct ast_filestream *, struct ast_frame *),
75 struct ast_frame * (*read)(struct ast_filestream *),
76 void (*close)(struct ast_filestream *),
77 char * (*getcomment)(struct ast_filestream *))
79 struct ast_format *tmp;
80 if (pthread_mutex_lock(&formatlock)) {
81 ast_log(LOG_WARNING, "Unable to lock format list\n");
86 if (!strcasecmp(name, tmp->name)) {
87 pthread_mutex_unlock(&formatlock);
88 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
93 tmp = malloc(sizeof(struct ast_format));
95 ast_log(LOG_WARNING, "Out of memory\n");
96 pthread_mutex_unlock(&formatlock);
99 strncpy(tmp->name, name, sizeof(tmp->name));
100 strncpy(tmp->exts, exts, sizeof(tmp->exts));
102 tmp->rewrite = rewrite;
107 tmp->format = format;
108 tmp->getcomment = getcomment;
111 pthread_mutex_unlock(&formatlock);
112 if (option_verbose > 1)
113 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
117 int ast_format_unregister(char *name)
119 struct ast_format *tmp, *tmpl = NULL;
120 if (pthread_mutex_lock(&formatlock)) {
121 ast_log(LOG_WARNING, "Unable to lock format list\n");
126 if (!strcasecmp(name, tmp->name)) {
128 tmpl->next = tmp->next;
132 pthread_mutex_unlock(&formatlock);
133 if (option_verbose > 1)
134 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
139 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
143 int ast_stopstream(struct ast_channel *tmp)
147 /* Stop a running stream if there is one */
150 tmp->stream->fmt->close(tmp->stream);
152 ast_translator_destroy(tmp);
157 int ast_closestream(struct ast_filestream *f)
160 ast_translator_free_path(f->trans);
162 /* Stop a running stream if there is one */
167 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
169 struct ast_frame_chain *fc, *f2;
172 if (f->frametype != AST_FRAME_VOICE) {
173 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
176 if ((fs->fmt->format & f->subclass) == f->subclass)
177 return fs->fmt->write(fs, f);
179 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
180 the one we've setup a translator for, we do the "wrong thing" XXX */
182 fs->trans = ast_translator_build_path(f->subclass, fs->fmt->format);
184 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %d\n", fs->fmt->name, f->subclass);
186 /* Build a chain of translated frames */
187 fc = ast_translate(fs->trans, f);
190 res = fs->fmt->write(fs, f2->fr);
192 ast_log(LOG_WARNING, "Frame write failed\n");
198 ast_log(LOG_DEBUG, "Count is %d\n", count);
207 static char *build_filename(char *filename, char *ext)
210 fn = malloc(strlen(AST_SOUNDS) + strlen(filename) + strlen(ext) + 10);
212 if (filename[0] == '/')
213 sprintf(fn, "%s.%s", filename, ext);
215 sprintf(fn, "%s/%s.%s", AST_SOUNDS, filename, ext);
221 #define ACTION_EXISTS 1
222 #define ACTION_DELETE 2
223 #define ACTION_RENAME 3
224 #define ACTION_OPEN 4
226 static int ast_filehelper(char *filename, char *filename2, char *fmt, int action)
229 struct ast_format *f;
230 struct ast_filestream *s;
232 char *ext=NULL, *exts, *fn, *nfn;
233 struct ast_channel *trans = (struct ast_channel *)filename2;
235 /* Start with negative response */
236 if (action == ACTION_EXISTS)
240 if (action == ACTION_OPEN)
242 /* Check for a specific format */
243 if (pthread_mutex_lock(&formatlock)) {
244 ast_log(LOG_WARNING, "Unable to lock format list\n");
245 if (action == ACTION_EXISTS)
252 if (!fmt || !strcasecmp(f->name, fmt)) {
253 exts = strdup(f->exts);
254 /* Try each kind of extension */
255 ext = strtok(exts, "|");
257 fn = build_filename(filename, ext);
268 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
271 nfn = build_filename(filename2, ext);
273 res = rename(fn, nfn);
275 ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
278 ast_log(LOG_WARNING, "Out of memory\n");
281 if ((ret < 0) && ((trans->format & f->format) /* == trans->format */)) {
282 ret = open(fn, O_RDONLY);
289 if (f->apply(trans, s)) {
291 trans->stream = NULL;
292 ast_log(LOG_WARNING, "Unable to apply stream to channel %s\n", trans->name);
298 ast_log(LOG_WARNING, "Unable to open fd on %s\n", filename);
301 ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
305 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
307 /* Conveniently this logic is the same for all */
313 ext = strtok(NULL, "|");
319 pthread_mutex_unlock(&formatlock);
320 if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
321 res = ret ? ret : -1;
325 int ast_fileexists(char *filename, char *fmt)
327 return ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
330 int ast_filedelete(char *filename, char *fmt)
332 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
335 int ast_filerename(char *filename, char *filename2, char *fmt)
337 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
340 int ast_streamfile(struct ast_channel *chan, char *filename)
342 /* This is a fairly complex routine. Essentially we should do
345 1) Find which file handlers produce our type of format.
346 2) Look for a filename which it can handle.
347 3) If we find one, then great.
348 *4) If not, see what files are there
349 *5) See what we can actually support
350 *6) Choose the one with the least costly translator path and
353 XXX * = unimplemented XXX
356 struct ast_channel *trans;
358 ast_stopstream(chan);
359 fmts = ast_fileexists(filename, NULL);
361 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
364 if (fmts & chan->format) {
365 /* No translation necessary -- we have a file in a format our channel can
370 fmts = ast_translator_best_choice(chan->format, fmts);
372 ast_log(LOG_WARNING, "Unable to find a translator method\n");
375 trans = ast_translator_create(chan, fmts, AST_DIRECTION_OUT);
377 ast_log(LOG_WARNING, "Unable to create translator\n");
381 fd = ast_filehelper(filename, (char *)trans, NULL, ACTION_OPEN);
384 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s'\n", filename);
388 ast_log(LOG_WARNING, "Unable to open %s (format %d): %s\n", filename, chan->format, strerror(errno));
390 ast_translator_destroy(trans);
395 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
398 struct ast_format *f;
399 struct ast_filestream *fs=NULL;
402 if (pthread_mutex_lock(&formatlock)) {
403 ast_log(LOG_WARNING, "Unable to lock format list\n");
408 if (!strcasecmp(f->name, type)) {
409 /* XXX Implement check XXX */
410 ext = strdup(f->exts);
411 ext = strtok(ext, "|");
412 fn = build_filename(filename, ext);
413 fd = open(fn, flags | O_WRONLY | O_CREAT, mode);
416 if ((fs = f->rewrite(fd, comment))) {
420 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
424 } else if (errno != EEXIST)
425 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
432 pthread_mutex_unlock(&formatlock);
434 ast_log(LOG_WARNING, "No such format '%s'\n", type);
438 char ast_waitstream(struct ast_channel *c, char *breakon)
441 struct ast_frame *fr;
445 res = ast_sched_wait(c->sched);
450 res = ast_waitfor(c, res);
452 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
459 ast_log(LOG_DEBUG, "Got hung up\n");
464 switch(fr->frametype) {
468 if (strchr(breakon, res))
471 case AST_FRAME_CONTROL:
472 switch(fr->subclass) {
473 case AST_CONTROL_HANGUP:
477 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
484 ast_sched_runq(c->sched);