Fri Aug 24 02:25:47 2007

Asterisk developer's documentation


file.c File Reference

Generic File Format Support. More...

#include "asterisk.h"
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include "asterisk/frame.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/sched.h"
#include "asterisk/options.h"
#include "asterisk/translate.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"

Include dependency graph for file.c:

Go to the source code of this file.

Defines

#define FORMAT   "%-10s %-10s %-20s\n"
#define FORMAT   "%-10s %-10s %-20s\n"
#define FORMAT2   "%-10s %-10s %-20s\n"
#define FORMAT2   "%-10s %-10s %-20s\n"

Enumerations

enum  file_action {
  ACTION_EXISTS = 1, ACTION_DELETE, ACTION_RENAME, ACTION_OPEN,
  ACTION_COPY
}
enum  wrap_fn { WRAP_OPEN, WRAP_REWRITE }

Functions

int __ast_format_register (const struct ast_format *f, struct ast_module *mod)
int ast_applystream (struct ast_channel *chan, struct ast_filestream *s)
int ast_closestream (struct ast_filestream *f)
int ast_file_init (void)
int ast_filecopy (const char *filename, const char *filename2, const char *fmt)
int ast_filedelete (const char *filename, const char *fmt)
int ast_fileexists (const char *filename, const char *fmt, const char *preflang)
static int ast_filehelper (const char *filename, const void *arg2, const char *fmt, const enum file_action action)
 perform various actions on a file. Second argument arg2 depends on the command: unused for EXISTS and DELETE destination file name (const char *) for COPY and RENAME struct ast_channel * for OPEN if fmt is NULL, OPEN will return the first matching entry, whereas other functions will run on all matching entries.
int ast_filerename (const char *filename, const char *filename2, const char *fmt)
int ast_format_unregister (const char *name)
ast_filestreamast_openstream (struct ast_channel *chan, const char *filename, const char *preflang)
ast_filestreamast_openstream_full (struct ast_channel *chan, const char *filename, const char *preflang, int asis)
ast_filestreamast_openvstream (struct ast_channel *chan, const char *filename, const char *preflang)
int ast_playstream (struct ast_filestream *s)
static int ast_readaudio_callback (void *data)
ast_filestreamast_readfile (const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
ast_frameast_readframe (struct ast_filestream *s)
static int ast_readvideo_callback (void *data)
static AST_RWLIST_HEAD_STATIC (formats, ast_format)
int ast_seekstream (struct ast_filestream *fs, off_t sample_offset, int whence)
int ast_stopstream (struct ast_channel *tmp)
int ast_stream_and_wait (struct ast_channel *chan, const char *file, const char *language, const char *digits)
int ast_stream_fastforward (struct ast_filestream *fs, off_t ms)
int ast_stream_rewind (struct ast_filestream *fs, off_t ms)
int ast_streamfile (struct ast_channel *chan, const char *filename, const char *preflang)
off_t ast_tellstream (struct ast_filestream *fs)
int ast_truncstream (struct ast_filestream *fs)
int ast_waitstream (struct ast_channel *c, const char *breakon)
int ast_waitstream_exten (struct ast_channel *c, const char *context)
int ast_waitstream_fr (struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
int ast_waitstream_full (struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
ast_filestreamast_writefile (const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
int ast_writestream (struct ast_filestream *fs, struct ast_frame *f)
static char * build_filename (const char *filename, const char *ext)
 construct a filename. Absolute pathnames are preserved, relative names are prefixed by the sounds/ directory. The wav49 suffix is replaced by 'WAV'. Returns a malloc'ed string to be freed by the caller.
static int copy (const char *infile, const char *outfile)
static int exts_compare (const char *exts, const char *type)
static int fileexists_core (const char *filename, const char *fmt, const char *preflang, char *buf, int buflen)
 helper routine to locate a file with a given format and language preference. Try preflang, preflang with stripped '_' suffix, or NULL. In the standard asterisk, language goes just before the last component. In an alternative configuration, the language should be a prefix to the actual filename.
static int fn_wrapper (struct ast_filestream *s, const char *comment, enum wrap_fn mode)
static struct ast_filestreamget_filestream (struct ast_format *fmt, FILE *bfile)
static int open_wrapper (struct ast_filestream *s)
static int rewrite_wrapper (struct ast_filestream *s, const char *comment)
static int show_file_formats (int fd, int argc, char *argv[])
static int show_file_formats_deprecated (int fd, int argc, char *argv[])
static int waitstream_core (struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int skip_ms, int audiofd, int cmdfd, const char *context)
 the core of all waitstream() functions

Variables

int ast_language_is_prefix = 1
ast_cli_entry cli_file []
ast_cli_entry cli_show_file_formats_deprecated
char show_file_formats_usage []


Detailed Description

Generic File Format Support.

Author:
Mark Spencer <markster@digium.com>

Definition in file file.c.


Define Documentation

#define FORMAT   "%-10s %-10s %-20s\n"

#define FORMAT   "%-10s %-10s %-20s\n"

#define FORMAT2   "%-10s %-10s %-20s\n"

#define FORMAT2   "%-10s %-10s %-20s\n"

Referenced by __iax2_show_peers(), __sip_show_channels(), _sip_show_peers(), dundi_show_mappings(), dundi_show_peers(), dundi_show_precache(), dundi_show_requests(), dundi_show_trans(), iax2_show_channels(), iax2_show_firmware(), iax2_show_registry(), iax2_show_users(), show_file_formats(), show_file_formats_deprecated(), show_image_formats(), show_image_formats_deprecated(), sip_show_inuse(), sip_show_registry(), zap_show_channels(), and zap_show_status().


Enumeration Type Documentation

enum file_action

Enumerator:
ACTION_EXISTS 
ACTION_DELETE 
ACTION_RENAME 
ACTION_OPEN 
ACTION_COPY 

Definition at line 331 of file file.c.

00331                  {
00332    ACTION_EXISTS = 1, /* return matching format if file exists, 0 otherwise */
00333    ACTION_DELETE, /* delete file, return 0 on success, -1 on error */
00334    ACTION_RENAME, /* rename file. return 0 on success, -1 on error */
00335    ACTION_OPEN,
00336    ACTION_COPY /* copy file. return 0 on success, -1 on error */
00337 };

enum wrap_fn

Enumerator:
WRAP_OPEN 
WRAP_REWRITE 

Definition at line 302 of file file.c.

00302 { WRAP_OPEN, WRAP_REWRITE };


Function Documentation

int __ast_format_register ( const struct ast_format f,
struct ast_module mod 
)

Register a new file format capability Adds a format to Asterisk's format abilities. returns 0 on success, -1 on failure

Definition at line 68 of file file.c.

References ast_calloc, ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verbose(), ast_format::buf_size, ast_format::exts, f, LOG_WARNING, ast_format::module, ast_format::name, option_verbose, and VERBOSE_PREFIX_2.

00069 {
00070    struct ast_format *tmp;
00071 
00072    AST_RWLIST_WRLOCK(&formats);
00073    AST_RWLIST_TRAVERSE(&formats, tmp, list) {
00074       if (!strcasecmp(f->name, tmp->name)) {
00075          AST_RWLIST_UNLOCK(&formats);
00076          ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", f->name);
00077          return -1;
00078       }
00079    }
00080    if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
00081       AST_RWLIST_UNLOCK(&formats);
00082       return -1;
00083    }
00084    *tmp = *f;
00085    tmp->module = mod;
00086    if (tmp->buf_size) {
00087       /*
00088        * Align buf_size properly, rounding up to the machine-specific
00089        * alignment for pointers.
00090        */
00091       struct _test_align { void *a, *b; } p;
00092       int align = (char *)&p.b - (char *)&p.a;
00093       tmp->buf_size = ((f->buf_size + align - 1)/align)*align;
00094    }
00095    
00096    memset(&tmp->list, 0, sizeof(tmp->list));
00097 
00098    AST_RWLIST_INSERT_HEAD(&formats, tmp, list);
00099    AST_RWLIST_UNLOCK(&formats);
00100    if (option_verbose > 1)
00101       ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", f->name, f->exts);
00102 
00103    return 0;
00104 }

int ast_applystream ( struct ast_channel chan,
struct ast_filestream s 
)

Parameters:
chan channel to work
s ast_filestream to apply Returns 0 for success, -1 on failure

Definition at line 660 of file file.c.

References s.

Referenced by ast_streamfile(), handle_getoption(), handle_recordfile(), handle_streamfile(), and speech_streamfile().

00661 {
00662    s->owner = chan;
00663    return 0;
00664 }

int ast_closestream ( struct ast_filestream f  ) 

Parameters:
f filestream to close Close a playback or recording stream Returns 0 on success, -1 on failure

Definition at line 700 of file file.c.

References ast_closestream(), AST_FORMAT_MAX_AUDIO, ast_module_unref(), ast_safe_system(), ast_sched_del(), ast_settimeout(), ast_translator_free_path(), ast_format::close, f, ast_format::format, free, and ast_format::module.

Referenced by __ast_play_and_record(), ast_closestream(), ast_filehelper(), ast_hangup(), ast_moh_files_next(), ast_monitor_start(), ast_monitor_stop(), ast_stopstream(), channel_spy(), cli_audio_convert(), cli_audio_convert_deprecated(), dictate_exec(), gen_closestream(), handle_recordfile(), local_ast_moh_stop(), mixmonitor_thread(), moh_files_release(), and rpt().

00701 {
00702    char *cmd = NULL;
00703    size_t size = 0;
00704    /* Stop a running stream if there is one */
00705    if (f->owner) {
00706       if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
00707          f->owner->stream = NULL;
00708          if (f->owner->streamid > -1)
00709             ast_sched_del(f->owner->sched, f->owner->streamid);
00710          f->owner->streamid = -1;
00711 #ifdef HAVE_ZAPTEL
00712          ast_settimeout(f->owner, 0, NULL, NULL);
00713 #endif         
00714       } else {
00715          f->owner->vstream = NULL;
00716          if (f->owner->vstreamid > -1)
00717             ast_sched_del(f->owner->sched, f->owner->vstreamid);
00718          f->owner->vstreamid = -1;
00719       }
00720    }
00721    /* destroy the translator on exit */
00722    if (f->trans)
00723       ast_translator_free_path(f->trans);
00724 
00725    if (f->realfilename && f->filename) {
00726          size = strlen(f->filename) + strlen(f->realfilename) + 15;
00727          cmd = alloca(size);
00728          memset(cmd,0,size);
00729          snprintf(cmd,size,"/bin/mv -f %s %s",f->filename,f->realfilename);
00730          ast_safe_system(cmd);
00731    }
00732 
00733    if (f->filename)
00734       free(f->filename);
00735    if (f->realfilename)
00736       free(f->realfilename);
00737    if (f->fmt->close)
00738       f->fmt->close(f);
00739    fclose(f->f);
00740    if (f->vfs)
00741       ast_closestream(f->vfs);
00742    ast_module_unref(f->fmt->module);
00743    free(f);
00744    return 0;
00745 }

int ast_file_init ( void   ) 

Initializes all the various file stuff. Basically just registers the cli stuff Returns 0 all the time

Definition at line 1205 of file file.c.

References ast_cli_register_multiple(), and cli_file.

Referenced by main().

01206 {
01207    ast_cli_register_multiple(cli_file, sizeof(cli_file) / sizeof(struct ast_cli_entry));
01208    return 0;
01209 }

int ast_filecopy ( const char *  oldname,
const char *  newname,
const char *  fmt 
)

Parameters:
oldname name of the file you wish to copy (minus extension)
newname name you wish the file to be copied to (minus extension)
fmt the format of the file Copy a given file in a given format, or if fmt is NULL, then do so for all

Definition at line 775 of file file.c.

References ast_filehelper().

Referenced by copy_file().

00776 {
00777    return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
00778 }

int ast_filedelete ( const char *  filename,
const char *  fmt 
)

Parameters:
filename name of the file you wish to delete (minus the extension)
fmt of the file Delete a given file in a given format, or if fmt is NULL, then do so for all

Definition at line 765 of file file.c.

References ACTION_DELETE, and ast_filehelper().

Referenced by __ast_play_and_record(), ast_monitor_start(), ast_monitor_stop(), cli_audio_convert(), cli_audio_convert_deprecated(), leave_voicemail(), play_mailbox_owner(), play_record_review(), and vm_delete().

00766 {
00767    return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
00768 }

int ast_fileexists ( const char *  filename,
const char *  fmt,
const char *  preflang 
)

Parameters:
filename name of the file you wish to check, minus the extension
fmt the format you wish to check (the extension)
preflang (the preferred language you wisht to find the file in) See if a given file exists in a given format. If fmt is NULL, any format is accepted. Returns -1 if file does not exist, non-zero positive otherwise.

Definition at line 751 of file file.c.

References fileexists_core().

Referenced by app_exec(), ast_moh_files_next(), ast_monitor_start(), ast_monitor_stop(), common_exec(), conf_run(), invent_message(), last_message_index(), leave_voicemail(), play_mailbox_owner(), play_message_callerid(), record_exec(), retrydial_exec(), rxfax_exec(), say_character_str_full(), say_digit_str_full(), say_phonetic_str_full(), vm_intro(), vm_newuser(), and vm_tempgreeting().

00752 {
00753    char *buf;
00754    int buflen;
00755 
00756    if (preflang == NULL)
00757       preflang = "";
00758    buflen = strlen(preflang) + strlen(filename) + 2;  /* room for everything */
00759    buf = alloca(buflen);
00760    if (buf == NULL)
00761       return 0;
00762    return fileexists_core(filename, fmt, preflang, buf, buflen);
00763 }

static int ast_filehelper ( const char *  filename,
const void *  arg2,
const char *  fmt,
const enum file_action  action 
) [static]

perform various actions on a file. Second argument arg2 depends on the command: unused for EXISTS and DELETE destination file name (const char *) for COPY and RENAME struct ast_channel * for OPEN if fmt is NULL, OPEN will return the first matching entry, whereas other functions will run on all matching entries.

Definition at line 348 of file file.c.

References ACTION_DELETE, ACTION_EXISTS, ACTION_OPEN, ACTION_RENAME, ast_closestream(), AST_FORMAT_MAX_AUDIO, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdupa, build_filename(), copy(), ext, ast_format::exts, exts_compare(), f, ast_format::format, free, get_filestream(), LOG_WARNING, open_wrapper(), s, ast_channel::stream, strsep(), ast_channel::vstream, and ast_channel::writeformat.

Referenced by ast_filecopy(), ast_filedelete(), ast_filerename(), ast_openstream_full(), ast_openvstream(), and fileexists_core().

00349 {
00350    struct ast_format *f;
00351    int res = (action == ACTION_EXISTS) ? 0 : -1;
00352 
00353    AST_RWLIST_RDLOCK(&formats);
00354    /* Check for a specific format */
00355    AST_RWLIST_TRAVERSE(&formats, f, list) {
00356       char *stringp, *ext = NULL;
00357 
00358       if (fmt && !exts_compare(f->exts, fmt))
00359          continue;
00360 
00361       /* Look for a file matching the supported extensions.
00362        * The file must exist, and for OPEN, must match
00363        * one of the formats supported by the channel.
00364        */
00365       stringp = ast_strdupa(f->exts);  /* this is in the stack so does not need to be freed */
00366       while ( (ext = strsep(&stringp, "|")) ) {
00367          struct stat st;
00368          char *fn = build_filename(filename, ext);
00369 
00370          if (fn == NULL)
00371             continue;
00372 
00373          if ( stat(fn, &st) ) { /* file not existent */
00374             free(fn);
00375             continue;
00376          }
00377          /* for 'OPEN' we need to be sure that the format matches
00378           * what the channel can process
00379           */
00380          if (action == ACTION_OPEN) {
00381             struct ast_channel *chan = (struct ast_channel *)arg2;
00382             FILE *bfile;
00383             struct ast_filestream *s;
00384 
00385             if ( !(chan->writeformat & f->format) &&
00386                  !(f->format >= AST_FORMAT_MAX_AUDIO && fmt)) {
00387                free(fn);
00388                continue;   /* not a supported format */
00389             }
00390             if ( (bfile = fopen(fn, "r")) == NULL) {
00391                free(fn);
00392                continue;   /* cannot open file */
00393             }
00394             s = get_filestream(f, bfile);
00395             if (!s) {
00396                fclose(bfile);
00397                free(fn);   /* cannot allocate descriptor */
00398                continue;
00399             }
00400             if (open_wrapper(s)) {
00401                fclose(bfile);
00402                free(fn);
00403                free(s);
00404                continue;   /* cannot run open on file */
00405             }
00406             /* ok this is good for OPEN */
00407             res = 1; /* found */
00408             s->lasttimeout = -1;
00409             s->fmt = f;
00410             s->trans = NULL;
00411             s->filename = NULL;
00412             if (s->fmt->format < AST_FORMAT_MAX_AUDIO) {
00413                if (chan->stream)
00414                   ast_closestream(chan->stream);
00415                chan->stream = s;
00416             } else {
00417                if (chan->vstream)
00418                   ast_closestream(chan->vstream);
00419                chan->vstream = s;
00420             }
00421             free(fn);
00422             break;
00423          }
00424          switch (action) {
00425          case ACTION_OPEN:
00426             break;   /* will never get here */
00427 
00428          case ACTION_EXISTS:  /* return the matching format */
00429             res |= f->format;
00430             break;
00431 
00432          case ACTION_DELETE:
00433             if ( (res = unlink(fn)) )
00434                ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
00435             break;
00436 
00437          case ACTION_RENAME:
00438          case ACTION_COPY: {
00439             char *nfn = build_filename((const char *)arg2, ext);
00440             if (!nfn)
00441                ast_log(LOG_WARNING, "Out of memory\n");
00442             else {
00443                res = action == ACTION_COPY ? copy(fn, nfn) : rename(fn, nfn);
00444                if (res)
00445                   ast_log(LOG_WARNING, "%s(%s,%s) failed: %s\n",
00446                      action == ACTION_COPY ? "copy" : "rename",
00447                       fn, nfn, strerror(errno));
00448                free(nfn);
00449             }
00450              }
00451             break;
00452 
00453          default:
00454             ast_log(LOG_WARNING, "Unknown helper %d\n", action);
00455          }
00456          free(fn);
00457       }
00458    }
00459    AST_RWLIST_UNLOCK(&formats);
00460    return res;
00461 }

int ast_filerename ( const char *  oldname,
const char *  newname,
const char *  fmt 
)

Parameters:
oldname the name of the file you wish to act upon (minus the extension)
newname the name you wish to rename the file to (minus the extension)
fmt the format of the file Rename a given file in a given format, or if fmt is NULL, then do so for all Returns -1 on failure

Definition at line 770 of file file.c.

References ACTION_RENAME, and ast_filehelper().

Referenced by __ast_play_and_record(), ast_monitor_stop(), leave_voicemail(), play_record_review(), and rename_file().

00771 {
00772    return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
00773 }

int ast_format_unregister ( const char *  name  ) 

Parameters:
name the name of the format you wish to unregister Unregisters a format based on the name of the format. Returns 0 on success, -1 on failure to unregister

Definition at line 106 of file file.c.

References ast_log(), AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verbose(), free, LOG_WARNING, ast_format::name, option_verbose, and VERBOSE_PREFIX_2.

Referenced by unload_module().

00107 {
00108    struct ast_format *tmp;
00109    int res = -1;
00110 
00111    AST_RWLIST_WRLOCK(&formats);
00112    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&formats, tmp, list) {
00113       if (!strcasecmp(name, tmp->name)) {
00114          AST_RWLIST_REMOVE_CURRENT(&formats, list);
00115          free(tmp);
00116          res = 0;
00117       }
00118    }
00119    AST_RWLIST_TRAVERSE_SAFE_END
00120    AST_RWLIST_UNLOCK(&formats);
00121 
00122    if (!res) {
00123       if (option_verbose > 1)
00124          ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
00125    } else
00126       ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
00127 
00128    return res;
00129 }

struct ast_filestream* ast_openstream ( struct ast_channel chan,
const char *  filename,
const char *  preflang 
)

Parameters:
chan channel to work with
filename to use
preflang prefered language to use Returns a ast_filestream pointer if it opens the file, NULL on error

Definition at line 523 of file file.c.

References ast_openstream_full().

Referenced by ast_streamfile(), dictate_exec(), handle_getoption(), handle_streamfile(), and speech_streamfile().

00524 {
00525    return ast_openstream_full(chan, filename, preflang, 0);
00526 }

struct ast_filestream* ast_openstream_full ( struct ast_channel chan,
const char *  filename,
const char *  preflang,
int  asis 
)

Parameters:
chan channel to work with
filename to use
preflang prefered language to use
asis if set, don't clear generators Returns a ast_filestream pointer if it opens the file, NULL on error

Definition at line 528 of file file.c.

References ACTION_OPEN, ast_deactivate_generator(), ast_filehelper(), AST_FORMAT_AUDIO_MASK, ast_log(), ast_set_write_format(), ast_stopstream(), ast_filestream::buf, fileexists_core(), LOG_WARNING, ast_channel::oldwriteformat, ast_channel::stream, and ast_channel::writeformat.

Referenced by ast_moh_files_next(), ast_openstream(), channel_spy(), and gen_nextfile().

00529 {
00530    /* 
00531     * Use fileexists_core() to find a file in a compatible
00532     * language and format, set up a suitable translator,
00533     * and open the stream.
00534     */
00535    int fmts, res, buflen;
00536    char *buf;
00537 
00538    if (!asis) {
00539       /* do this first, otherwise we detect the wrong writeformat */
00540       ast_stopstream(chan);
00541       if (chan->generator)
00542          ast_deactivate_generator(chan);
00543    }
00544    if (preflang == NULL)
00545       preflang = "";
00546    buflen = strlen(preflang) + strlen(filename) + 2;
00547    buf = alloca(buflen);
00548    if (buf == NULL)
00549       return NULL;
00550    fmts = fileexists_core(filename, NULL, preflang, buf, buflen);
00551    if (fmts > 0)
00552       fmts &= AST_FORMAT_AUDIO_MASK;
00553    if (fmts < 1) {
00554       ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
00555       return NULL;
00556    }
00557    chan->oldwriteformat = chan->writeformat;
00558    /* Set the channel to a format we can work with */
00559    res = ast_set_write_format(chan, fmts);
00560    res = ast_filehelper(buf, chan, NULL, ACTION_OPEN);
00561    if (res >= 0)
00562       return chan->stream;
00563    return NULL;
00564 }

struct ast_filestream* ast_openvstream ( struct ast_channel chan,
const char *  filename,
const char *  preflang 
)

Parameters:
chan channel to work with
filename to use
preflang prefered language to use Returns a ast_filestream pointer if it opens the file, NULL on error

Definition at line 566 of file file.c.

References ACTION_OPEN, ast_filehelper(), AST_FORMAT_MAX_AUDIO, AST_FORMAT_MAX_VIDEO, ast_getformatname(), ast_log(), ast_filestream::buf, fileexists_core(), fmt, format, LOG_WARNING, ast_channel::nativeformats, and ast_channel::vstream.

Referenced by ast_streamfile(), handle_getoption(), and handle_streamfile().

00567 {
00568    /* As above, but for video. But here we don't have translators
00569     * so we must enforce a format.
00570     */
00571    unsigned int format;
00572    char *buf;
00573    int buflen;
00574 
00575    if (preflang == NULL)
00576       preflang = "";
00577    buflen = strlen(preflang) + strlen(filename) + 2;
00578    buf = alloca(buflen);
00579    if (buf == NULL)
00580       return NULL;
00581 
00582    for (format = AST_FORMAT_MAX_AUDIO << 1; format <= AST_FORMAT_MAX_VIDEO; format = format << 1) {
00583       int fd;
00584       const char *fmt;
00585 
00586       if (!(chan->nativeformats & format))
00587          continue;
00588       fmt = ast_getformatname(format);
00589       if ( fileexists_core(filename, fmt, preflang, buf, buflen) < 1)   /* no valid format */
00590          continue;
00591       fd = ast_filehelper(buf, chan, fmt, ACTION_OPEN);
00592       if (fd >= 0)
00593          return chan->vstream;
00594       ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
00595    }
00596    return NULL;
00597 }

int ast_playstream ( struct ast_filestream s  ) 

Parameters:
s filestream to play Returns 0 for success, -1 on failure

Definition at line 666 of file file.c.

References AST_FORMAT_MAX_AUDIO, ast_readaudio_callback(), ast_readvideo_callback(), and s.

Referenced by ast_streamfile(), handle_getoption(), handle_streamfile(), and speech_streamfile().

00667 {
00668    if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00669       ast_readaudio_callback(s);
00670    else
00671       ast_readvideo_callback(s);
00672    return 0;
00673 }

static int ast_readaudio_callback ( void *  data  )  [static]

Definition at line 608 of file file.c.

References ast_log(), ast_sched_add(), ast_settimeout(), ast_write(), LOG_WARNING, and s.

Referenced by ast_playstream().

00609 {
00610    struct ast_filestream *s = data;
00611    int whennext = 0;
00612 
00613    while(!whennext) {
00614       struct ast_frame *fr = s->fmt->read(s, &whennext);
00615       if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
00616          if (fr)
00617             ast_log(LOG_WARNING, "Failed to write frame\n");
00618          s->owner->streamid = -1;
00619 #ifdef HAVE_ZAPTEL
00620          ast_settimeout(s->owner, 0, NULL, NULL);
00621 #endif         
00622          return 0;
00623       }
00624    }
00625    if (whennext != s->lasttimeout) {
00626 #ifdef HAVE_ZAPTEL
00627       if (s->owner->timingfd > -1)
00628          ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
00629       else
00630 #endif      
00631          s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
00632       s->lasttimeout = whennext;
00633       return 0;
00634    }
00635    return 1;
00636 }

struct ast_filestream* ast_readfile ( const char *  filename,
const char *  type,
const char *  comment,
int  flags,
int  check,
mode_t  mode 
)

Parameters:
filename the name of the file to read from
type format of file you wish to read from
comment comment to go with
flags file flags
check (unimplemented, hence negligible)
mode Open mode Open an incoming file stream. flags are flags for the open() command, and if check is non-zero, then it will not read a file if there are any files that start with that name and have an extension Please note, this is a blocking function. Program execution will not return until ast_waitstream completes it's execution. Returns a struct ast_filestream on success, NULL on failure

Definition at line 808 of file file.c.

References ast_free, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, build_filename(), ast_format::exts, exts_compare(), f, ast_filestream::filename, ast_filestream::flags, ast_filestream::fmt, free, get_filestream(), LOG_WARNING, ast_filestream::mode, open_wrapper(), strdup, ast_filestream::trans, and ast_filestream::vfs.

Referenced by __ast_play_and_record(), cli_audio_convert(), and cli_audio_convert_deprecated().

00809 {
00810    FILE *bfile;
00811    struct ast_format *f;
00812    struct ast_filestream *fs = NULL;
00813    char *fn;
00814 
00815    AST_RWLIST_RDLOCK(&formats);
00816 
00817    AST_RWLIST_TRAVERSE(&formats, f, list) {
00818       fs = NULL;
00819       if (!exts_compare(f->exts, type))
00820          continue;
00821 
00822       fn = build_filename(filename, type);
00823       errno = 0;
00824       bfile = fopen(fn, "r");
00825       if (!bfile || (fs = get_filestream(f, bfile)) == NULL ||
00826           open_wrapper(fs) ) {
00827          ast_log(LOG_WARNING, "Unable to open %s\n", fn);
00828          if (fs)
00829             ast_free(fs);
00830          if (bfile)
00831             fclose(bfile);
00832          free(fn);
00833          continue;
00834       }
00835       /* found it */
00836       fs->trans = NULL;
00837       fs->fmt = f;
00838       fs->flags = flags;
00839       fs->mode = mode;
00840       fs->filename = strdup(filename);
00841       fs->vfs = NULL;
00842       break;
00843    }
00844 
00845    AST_RWLIST_UNLOCK(&formats);
00846    if (!fs) 
00847       ast_log(LOG_WARNING, "No such format '%s'\n", type);
00848 
00849    return fs;
00850 }

struct ast_frame* ast_readframe ( struct ast_filestream s  ) 

Parameters:
s ast_filestream to act on Returns a frame or NULL if read failed

Definition at line 599 of file file.c.

References f, and s.

Referenced by __ast_play_and_record(), channel_spy(), cli_audio_convert(), cli_audio_convert_deprecated(), dictate_exec(), gen_readframe(), and moh_files_readframe().

00600 {
00601    struct ast_frame *f = NULL;
00602    int whennext = 0; 
00603    if (s && s->fmt)
00604       f = s->fmt->read(s, &whennext);
00605    return f;
00606 }

static int ast_readvideo_callback ( void *  data  )  [static]

Definition at line 638 of file file.c.

References ast_log(), ast_sched_add(), ast_write(), LOG_WARNING, and s.

Referenced by ast_playstream().

00639 {
00640    struct ast_filestream *s = data;
00641    int whennext = 0;
00642 
00643    while (!whennext) {
00644       struct ast_frame *fr = s->fmt->read(s, &whennext);
00645       if (!fr || ast_write(s->owner, fr)) { /* no stream or error, as above */
00646          if (fr)
00647             ast_log(LOG_WARNING, "Failed to write frame\n");
00648          s->owner->vstreamid = -1;
00649          return 0;
00650       }
00651    }
00652    if (whennext != s->lasttimeout) {
00653       s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
00654       s->lasttimeout = whennext;
00655       return 0;
00656    }
00657    return 1;
00658 }

static AST_RWLIST_HEAD_STATIC ( formats  ,
ast_format   
) [static]

int ast_seekstream ( struct ast_filestream fs,
off_t  sample_offset,
int  whence 
)

Parameters:
fs ast_filestream to perform seek on
sample_offset numbers of samples to seek
whence SEEK_SET, SEEK_CUR, SEEK_END Returns 0 for success, or -1 for error

Definition at line 675 of file file.c.

References ast_filestream::fmt, and ast_format::seek.

Referenced by __ast_read(), ast_control_streamfile(), ast_stream_fastforward(), ast_stream_rewind(), ast_write(), dictate_exec(), handle_getoption(), handle_recordfile(), and handle_streamfile().

00676 {
00677    return fs->fmt->seek(fs, sample_offset, whence);
00678 }

int ast_stopstream ( struct ast_channel c  ) 

Parameters:
c The channel you wish to stop playback on Stop playback of a stream Returns 0 regardless

Definition at line 131 of file file.c.

References ast_closestream(), ast_log(), ast_set_write_format(), LOG_WARNING, ast_channel::oldwriteformat, ast_channel::stream, and ast_channel::vstream.

Referenced by app_exec(), ast_adsi_transmit_message_full(), ast_app_getdata(), ast_control_streamfile(), ast_openstream_full(), ast_play_and_wait(), ast_readstring_full(), ast_say_enumeration_full_da(), ast_say_enumeration_full_de(), ast_say_enumeration_full_en(), ast_say_number_full_cz(), ast_say_number_full_da(), ast_say_number_full_de(), ast_say_number_full_en(), ast_say_number_full_en_GB(), ast_say_number_full_es(), ast_say_number_full_fr(), ast_say_number_full_ge(), ast_say_number_full_gr(), ast_say_number_full_he(), ast_say_number_full_it(), ast_say_number_full_nl(), ast_say_number_full_no(), ast_say_number_full_pt(), ast_say_number_full_ru(), ast_say_number_full_se(), ast_say_number_full_tw(), background_detect_exec(), builtin_blindtransfer(), conf_exec(), conf_run(), directory_exec(), handle_getoption(), handle_streamfile(), ices_exec(), ivr_dispatch(), leave_voicemail(), mp3_exec(), NBScat_exec(), nv_background_detect_exec(), parkandannounce_exec(), pbx_builtin_background(), pl_odtworz_plik(), play_file(), play_mailbox_owner(), playback_exec(), queue_exec(), read_exec(), recordthread(), rpt_tele_thread(), s_streamwait3(), say_character_str_full(), say_digit_str_full(), say_phonetic_str_full(), saycharstr(), sayfile(), saynum(), send_morse(), send_tone_telemetry(), send_waveform_to_channel(), speech_background(), vm_authenticate(), vm_execmain(), wait_for_winner(), waitstream_core(), and zapateller_exec().

00132 {
00133    /* Stop a running stream if there is one */
00134    if (tmp->stream) {
00135       ast_closestream(tmp->stream);
00136       tmp->stream = NULL;
00137       if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
00138          ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
00139    }
00140    /* Stop the video stream too */
00141    if (tmp->vstream != NULL) {
00142       ast_closestream(tmp->vstream);
00143       tmp->vstream = NULL;
00144    }
00145    return 0;
00146 }

int ast_stream_and_wait ( struct ast_channel chan,
const char *  file,
const char *  language,
const char *  digits 
)

Definition at line 1128 of file file.c.

References ast_streamfile(), ast_strlen_zero(), and ast_waitstream().

Referenced by __ast_play_and_record(), app_exec(), ast_record_review(), bridge_playfile(), builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), directory_exec(), invent_message(), ivr_dispatch(), leave_voicemail(), park_exec(), play_mailbox_owner(), play_message_callerid(), play_record_review(), and wait_file2().

01130 {
01131         int res = 0;
01132         if (!ast_strlen_zero(file)) {
01133                 res =  ast_streamfile(chan, file, language);
01134                 if (!res)
01135                         res = ast_waitstream(chan, digits);
01136         }
01137         return res;
01138 } 

int ast_stream_fastforward ( struct ast_filestream fs,
off_t  ms 
)

Parameters:
fs filestream to act on
ms milliseconds to move Returns 0 for success, or -1 for error

Definition at line 690 of file file.c.

References ast_seekstream(), and DEFAULT_SAMPLES_PER_MS.

Referenced by waitstream_core().

00691 {
00692    return ast_seekstream(fs, ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
00693 }

int ast_stream_rewind ( struct ast_filestream fs,
off_t  ms 
)

Parameters:
fs filestream to act on
ms milliseconds to move Returns 0 for success, or -1 for error

Definition at line 695 of file file.c.

References ast_seekstream(), and DEFAULT_SAMPLES_PER_MS.

Referenced by __ast_play_and_record(), handle_recordfile(), and waitstream_core().

00696 {
00697    return ast_seekstream(fs, -ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
00698 }

int ast_streamfile ( struct ast_channel c,
const char *  filename,
const char *  preflang 
)

Parameters:
c channel to stream the file to
filename the name of the file you wish to stream, minus the extension
preflang the preferred language you wish to have the file streamed to you in Prepares a channel for the streaming of a file. To start the stream, afterward do a ast_waitstream() on the channel Also, it will stop any existing streams on the channel. Returns 0 on success, or -1 on failure.

Definition at line 780 of file file.c.

References ast_applystream(), ast_getformatname(), ast_getformatname_multiple(), ast_log(), ast_openstream(), ast_openvstream(), ast_playstream(), ast_verbose(), fmt, ast_filestream::fmt, ast_format::format, LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, option_verbose, VERBOSE_PREFIX_3, and ast_filestream::vfs.

Referenced by __login_exec(), agent_call(), app_exec(), ast_app_getdata(), ast_app_getdata_full(), ast_control_streamfile(), ast_play_and_wait(), ast_say_date_da(), ast_say_date_de(), ast_say_date_en(), ast_say_date_fr(), ast_say_date_ge(), ast_say_date_gr(), ast_say_date_nl(), ast_say_date_with_format_gr(), ast_say_datetime_en(), ast_say_datetime_fr(), ast_say_datetime_from_now_en(), ast_say_datetime_from_now_fr(), ast_say_datetime_from_now_ge(), ast_say_datetime_gr(), ast_say_datetime_nl(), ast_say_datetime_pt(), ast_say_datetime_tw(), ast_say_enumeration_full_da(), ast_say_enumeration_full_de(), ast_say_enumeration_full_en(), ast_say_number_full_cz(), ast_say_number_full_da(), ast_say_number_full_de(), ast_say_number_full_en(), ast_say_number_full_en_GB(), ast_say_number_full_es(), ast_say_number_full_fr(), ast_say_number_full_ge(), ast_say_number_full_gr(), ast_say_number_full_he(), ast_say_number_full_it(), ast_say_number_full_nl(), ast_say_number_full_no(), ast_say_number_full_pt(), ast_say_number_full_ru(), ast_say_number_full_se(), ast_say_number_full_tw(), ast_say_time_de(), ast_say_time_en(), ast_say_time_fr(), ast_say_time_ge(), ast_say_time_gr(), ast_say_time_nl(), ast_say_time_tw(), ast_stream_and_wait(), background_detect_exec(), check_availability(), check_beep(), common_exec(), conf_exec(), conf_run(), do_directory(), forward_message(), gr_say_number_female(), handle_recordfile(), leave_voicemail(), nv_background_detect_exec(), page_exec(), park_exec(), parkandannounce_exec(), pbx_builtin_background(), pl_odtworz_plik(), play_and_wait(), play_file(), playback_exec(), privacy_exec(), retrydial_exec(), rpt_tele_thread(), s_streamwait3(), say_character_str_full(), say_digit_str_full(), say_phonetic_str_full(), sayfile(), ss_thread(), vm_authenticate(), wait_file(), and wait_for_winner().

00781 {
00782    struct ast_filestream *fs;
00783    struct ast_filestream *vfs=NULL;
00784    char fmt[256];
00785 
00786    fs = ast_openstream(chan, filename, preflang);
00787    if (fs)
00788       vfs = ast_openvstream(chan, filename, preflang);
00789    if (vfs)
00790       ast_log(LOG_DEBUG, "Ooh, found a video stream, too, format %s\n", ast_getformatname(vfs->fmt->format));
00791    if (fs){
00792       if (ast_applystream(chan, fs))
00793          return -1;
00794       if (vfs && ast_applystream(chan, vfs))
00795          return -1;
00796       ast_playstream(fs);
00797       if (vfs)
00798          ast_playstream(vfs);
00799       if (option_verbose > 2)
00800          ast_verbose(VERBOSE_PREFIX_3 "<%s> Playing '%s' (language '%s')\n", chan->name, filename, preflang ? preflang : "default");
00801 
00802       return 0;
00803    }
00804    ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), chan->nativeformats), strerror(errno));
00805    return -1;
00806 }

off_t ast_tellstream ( struct ast_filestream fs  ) 

Parameters:
fs fs to act on Returns a long as a sample offset into stream

Definition at line 685 of file file.c.

References ast_filestream::fmt, and ast_format::tell.

Referenced by ast_control_streamfile(), handle_getoption(), handle_recordfile(), and handle_streamfile().

00686 {
00687    return fs->fmt->tell(fs);
00688 }

int ast_truncstream ( struct ast_filestream fs  ) 

Parameters:
fs filestream to act on Returns 0 for success, or -1 for error

Definition at line 680 of file file.c.

References ast_filestream::fmt, and ast_format::trunc.

Referenced by __ast_play_and_record(), and handle_recordfile().

00681 {
00682    return fs->fmt->trunc(fs);
00683 }

int ast_waitstream ( struct ast_channel c,
const char *  breakon 
)

Parameters:
c channel to waitstream on
breakon string of DTMF digits to break upon Begins playback of a stream... Wait for a stream to stop or for any one of a given digit to arrive, Returns 0 if the stream finishes, the character if it was interrupted, and -1 on error

Definition at line 1101 of file file.c.

References waitstream_core().

Referenced by __login_exec(), agent_call(), app_exec(), ast_app_getdata(), ast_play_and_wait(), ast_say_date_da(), ast_say_date_de(), ast_say_date_en(), ast_say_date_fr(), ast_say_date_ge(), ast_say_date_gr(), ast_say_date_nl(), ast_say_date_with_format_gr(), ast_say_datetime_en(), ast_say_datetime_fr(), ast_say_datetime_from_now_en(), ast_say_datetime_from_now_fr(), ast_say_datetime_from_now_ge(), ast_say_datetime_gr(), ast_say_datetime_nl(), ast_say_datetime_pt(), ast_say_datetime_tw(), ast_say_enumeration_full_da(), ast_say_enumeration_full_de(), ast_say_enumeration_full_en(), ast_say_number_full_cz(), ast_say_number_full_da(), ast_say_number_full_de(), ast_say_number_full_en(), ast_say_number_full_en_GB(), ast_say_number_full_es(), ast_say_number_full_fr(), ast_say_number_full_ge(), ast_say_number_full_gr(), ast_say_number_full_he(), ast_say_number_full_it(), ast_say_number_full_nl(), ast_say_number_full_no(), ast_say_number_full_pt(), ast_say_number_full_ru(), ast_say_number_full_se(), ast_say_number_full_tw(), ast_say_time_de(), ast_say_time_en(), ast_say_time_ge(), ast_say_time_gr(), ast_say_time_nl(), ast_say_time_tw(), ast_stream_and_wait(), check_availability(), check_beep(), common_exec(), conf_exec(), conf_run(), directory_exec(), gr_say_number_female(), handle_recordfile(), leave_voicemail(), page_exec(), park_exec(), parkandannounce_exec(), pbx_builtin_background(), pl_odtworz_plik(), play_and_wait(), play_file(), playback_exec(), privacy_exec(), retrydial_exec(), rpt_tele_thread(), s_streamwait3(), say_character_str_full(), say_digit_str_full(), say_phonetic_str_full(), saycharstr(), sayfile(), saynum(), send_morse(), send_tone_telemetry(), ss_thread(), vm_authenticate(), and wait_file().

01102 {
01103    return waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL);
01104 }

int ast_waitstream_exten ( struct ast_channel c,
const char *  context 
)

Parameters:
c channel to waitstream on
context string of context to match digits to break upon Begins playback of a stream... Wait for a stream to stop or for any one of a valid extension digit to arrive, Returns 0 if the stream finishes, the character if it was interrupted, and -1 on error

Definition at line 1112 of file file.c.

References ast_channel::context, and waitstream_core().

Referenced by pbx_builtin_background().

01113 {
01114    /* Waitstream, with return in the case of a valid 1 digit extension */
01115    /* in the current or specified context being pressed */
01116 
01117    if (!context)
01118       context = c->context;
01119    return waitstream_core(c, NULL, NULL, NULL, 0,
01120       -1, -1, context);
01121 }

int ast_waitstream_fr ( struct ast_channel c,
const char *  breakon,
const char *  forward,
const char *  rewind,
int  ms 
)

Parameters:
c channel to waitstream on
breakon string of DTMF digits to break upon
forward DTMF digit to fast forward upon
rewind DTMF digit to rewind upon
ms How many miliseconds to skip forward/back Begins playback of a stream... Wait for a stream to stop or for any one of a given digit to arrive, Returns 0 if the stream finishes, the character if it was interrupted, and -1 on error

Definition at line 1095 of file file.c.

References waitstream_core().

Referenced by ast_control_streamfile().

01096 {
01097    return waitstream_core(c, breakon, forward, rewind, ms,
01098       -1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */);
01099 }

int ast_waitstream_full ( struct ast_channel c,
const char *  breakon,
int  audiofd,
int  cmdfd 
)

Definition at line 1106 of file file.c.

References waitstream_core().

Referenced by ast_readstring_full(), ast_say_enumeration_full_da(), ast_say_enumeration_full_de(), ast_say_enumeration_full_en(), ast_say_number_full_cz(), ast_say_number_full_da(), ast_say_number_full_de(), ast_say_number_full_en(), ast_say_number_full_en_GB(), ast_say_number_full_es(), ast_say_number_full_fr(), ast_say_number_full_ge(), ast_say_number_full_gr(), ast_say_number_full_he(), ast_say_number_full_it(), ast_say_number_full_nl(), ast_say_number_full_no(), ast_say_number_full_pt(), ast_say_number_full_ru(), ast_say_number_full_se(), ast_say_number_full_tw(), handle_getoption(), handle_streamfile(), pl_odtworz_plik(), s_streamwait3(), say_character_str_full(), say_digit_str_full(), and say_phonetic_str_full().

01107 {
01108    return waitstream_core(c, breakon, NULL, NULL, 0,
01109       audiofd, cmdfd, NULL /* no context */);
01110 }

struct ast_filestream* ast_writefile ( const char *  filename,
const char *  type,
const char *  comment,
int  flags,
int  check,
mode_t  mode 
)

Parameters:
filename the name of the file to write to
type format of file you wish to write out to
comment comment to go with
flags output file flags
check (unimplemented, hence negligible)
mode Open mode Create an outgoing file stream. oflags are flags for the open() command, and if check is non-zero, then it will not write a file if there are any files that start with that name and have an extension Please note, this is a blocking function. Program execution will not return until ast_waitstream completes it's execution. Returns a struct ast_filestream on success, NULL on failure

Definition at line 852 of file file.c.

References ast_free, ast_log(), ast_opt_cache_record_files, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdupa, ast_filestream::buf, build_filename(), ast_format::exts, exts_compare(), f, ast_filestream::filename, ast_filestream::flags, ast_filestream::fmt, free, get_filestream(), LOG_WARNING, ast_filestream::mode, ast_filestream::realfilename, record_cache_dir, rewrite_wrapper(), ast_format::seek, strdup, ast_filestream::trans, and ast_filestream::vfs.

Referenced by __ast_play_and_record(), ast_monitor_start(), ast_writestream(), cli_audio_convert(), cli_audio_convert_deprecated(), dictate_exec(), handle_recordfile(), mixmonitor_thread(), recordthread(), and rpt().

00853 {
00854    int fd, myflags = 0;
00855    /* compiler claims this variable can be used before initialization... */
00856    FILE *bfile = NULL;
00857    struct ast_format *f;
00858    struct ast_filestream *fs = NULL;
00859    char *buf = NULL;
00860    size_t size = 0;
00861    int format_found = 0;
00862 
00863    AST_RWLIST_RDLOCK(&formats);
00864 
00865    /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
00866    /* We really can't use O_APPEND as it will break WAV header updates */
00867    if (flags & O_APPEND) { 
00868       flags &= ~O_APPEND;
00869    } else {
00870       myflags = O_TRUNC;
00871    }
00872    
00873    myflags |= O_WRONLY | O_CREAT;
00874 
00875    /* XXX need to fix this - we should just do the fopen,
00876     * not open followed by fdopen()
00877     */
00878    AST_RWLIST_TRAVERSE(&formats, f, list) {
00879       char *fn, *orig_fn = NULL;
00880       if (fs)
00881          break;
00882 
00883       if (!exts_compare(f->exts, type))
00884          continue;
00885       else
00886          format_found = 1;
00887 
00888       fn = build_filename(filename, type);
00889       fd = open(fn, flags | myflags, mode);
00890       if (fd > -1) {
00891          /* fdopen() the resulting file stream */
00892          bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
00893          if (!bfile) {
00894             ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
00895             close(fd);
00896             fd = -1;
00897          }
00898       }
00899       
00900       if (ast_opt_cache_record_files && (fd > -1)) {
00901          char *c;
00902 
00903          fclose(bfile); /* this also closes fd */
00904          /*
00905            We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
00906            What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
00907          */
00908          orig_fn = ast_strdupa(fn);
00909          for (c = fn; *c; c++)
00910             if (*c == '/')
00911                *c = '_';
00912 
00913          size = strlen(fn) + strlen(record_cache_dir) + 2;
00914          buf = alloca(size);
00915          strcpy(buf, record_cache_dir);
00916          strcat(buf, "/");
00917          strcat(buf, fn);
00918          free(fn);
00919          fn = buf;
00920          fd = open(fn, flags | myflags, mode);
00921          if (fd > -1) {
00922             /* fdopen() the resulting file stream */
00923             bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
00924             if (!bfile) {
00925                ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
00926                close(fd);
00927                fd = -1;
00928             }
00929          }
00930       }
00931       if (fd > -1) {
00932          errno = 0;
00933          fs = get_filestream(f, bfile);
00934          if (!fs || rewrite_wrapper(fs, comment)) {
00935             ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
00936             close(fd);
00937             if (orig_fn) {
00938                unlink(fn);
00939                unlink(orig_fn);
00940             }
00941             if (fs)
00942                ast_free(fs);
00943             fs = NULL;
00944             continue;
00945          }
00946          fs->trans = NULL;
00947          fs->fmt = f;
00948          fs->flags = flags;
00949          fs->mode = mode;
00950          if (orig_fn) {
00951             fs->realfilename = strdup(orig_fn);
00952             fs->filename = strdup(fn);
00953          } else {
00954             fs->realfilename = NULL;
00955             fs->filename = strdup(filename);
00956          }
00957          fs->vfs = NULL;
00958          /* If truncated, we'll be at the beginning; if not truncated, then append */
00959          f->seek(fs, 0, SEEK_END);
00960       } else if (errno != EEXIST) {
00961          ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00962          if (orig_fn)
00963             unlink(orig_fn);
00964       }
00965       /* if buf != NULL then fn is already free and pointing to it */
00966       if (!buf)
00967          free(fn);
00968    }
00969 
00970    AST_RWLIST_UNLOCK(&formats);
00971 
00972    if (!format_found)
00973       ast_log(LOG_WARNING, "No such format '%s'\n", type);
00974 
00975    return fs;
00976 }

int ast_writestream ( struct ast_filestream fs,
struct ast_frame f 
)

Parameters:
fs filestream to write to
f frame to write to the filestream Send a frame to a filestream -- note: does NOT free the frame, call ast_frfree manually Returns 0 on success, -1 on failure.

Definition at line 148 of file file.c.

References AST_FORMAT_MAX_AUDIO, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_getformatname(), ast_log(), ast_translate(), ast_translator_build_path(), ast_translator_free_path(), ast_writefile(), ast_writestream(), f, ast_filestream::filename, ast_filestream::flags, ast_filestream::fmt, ast_format::format, ast_filestream::lastwriteformat, LOG_DEBUG, LOG_WARNING, ast_filestream::mode, ast_format::name, ast_filestream::trans, type, ast_filestream::vfs, and ast_format::write.

Referenced by __ast_play_and_record(), __ast_read(), ast_write(), ast_writestream(), cli_audio_convert(), cli_audio_convert_deprecated(), dictate_exec(), handle_recordfile(), mixmonitor_thread(), recordthread(), and rpt().

00149 {
00150    int res = -1;
00151    int alt = 0;
00152    if (f->frametype == AST_FRAME_VIDEO) {
00153       if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
00154          /* This is the audio portion.  Call the video one... */
00155          if (!fs->vfs && fs->filename) {
00156             const char *type = ast_getformatname(f->subclass & ~0x1);
00157             fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
00158             ast_log(LOG_DEBUG, "Opened video output file\n");
00159          }
00160          if (fs->vfs)
00161             return ast_writestream(fs->vfs, f);
00162          /* else ignore */
00163          return 0;            
00164       } else {
00165          /* Might / might not have mark set */
00166          alt = 1;
00167       }
00168    } else if (f->frametype != AST_FRAME_VOICE) {
00169       ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
00170       return -1;
00171    }
00172    if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
00173       res =  fs->fmt->write(fs, f);
00174       if (res < 0) 
00175          ast_log(LOG_WARNING, "Natural write failed\n");
00176       else if (res > 0)
00177          ast_log(LOG_WARNING, "Huh??\n");
00178    } else {
00179       /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
00180              the one we've setup a translator for, we do the "wrong thing" XXX */
00181       if (fs->trans && f->subclass != fs->lastwriteformat) {
00182          ast_translator_free_path(fs->trans);
00183          fs->trans = NULL;
00184       }
00185       if (!fs->trans) 
00186          fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
00187       if (!fs->trans)
00188          ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n",
00189             fs->fmt->name, ast_getformatname(f->subclass));
00190       else {
00191          struct ast_frame *trf;
00192          fs->lastwriteformat = f->subclass;
00193          /* Get the translated frame but don't consume the original in case they're using it on another stream */
00194          trf = ast_translate(fs->trans, f, 0);
00195          if (trf) {
00196             res = fs->fmt->write(fs, trf);
00197             if (res) 
00198                ast_log(LOG_WARNING, "Translated frame write failed\n");
00199          } else
00200             res = 0;
00201       }
00202    }
00203    return res;
00204 }

static char* build_filename ( const char *  filename,
const char *  ext 
) [static]

construct a filename. Absolute pathnames are preserved, relative names are prefixed by the sounds/ directory. The wav49 suffix is replaced by 'WAV'. Returns a malloc'ed string to be freed by the caller.

Definition at line 249 of file file.c.

References asprintf, and ast_config_AST_DATA_DIR.

Referenced by ast_filehelper(), ast_readfile(), and ast_writefile().

00250 {
00251    char *fn = NULL;
00252 
00253    if (!strcmp(ext, "wav49"))
00254       ext = "WAV";
00255 
00256    if (filename[0] == '/')
00257       asprintf(&fn, "%s.%s", filename, ext);
00258    else
00259       asprintf(&fn, "%s/sounds/%s.%s",
00260          ast_config_AST_DATA_DIR, filename, ext);
00261    return fn;
00262 }

static int copy ( const char *  infile,
const char *  outfile 
) [static]

Definition at line 206 of file file.c.

References ast_log(), len, and LOG_WARNING.

Referenced by action_getvar(), ast_filehelper(), copy_file(), and iax2_register().

00207 {
00208    int ifd, ofd, len;
00209    char buf[4096];   /* XXX make it lerger. */
00210 
00211    if ((ifd = open(infile, O_RDONLY)) < 0) {
00212       ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
00213       return -1;
00214    }
00215    if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
00216       ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
00217       close(ifd);
00218       return -1;
00219    }
00220    while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
00221       int res;
00222       if (len < 0) {
00223          ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
00224          break;
00225       }
00226       /* XXX handle partial writes */
00227       res = write(ofd, buf, len);
00228       if (res != len) {
00229          ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
00230          len = -1; /* error marker */
00231          break;
00232       }
00233    }
00234    close(ifd);
00235    close(ofd);
00236    if (len < 0) {
00237       unlink(outfile);
00238       return -1; /* error */
00239    }
00240    return 0;   /* success */
00241 }

static int exts_compare ( const char *  exts,
const char *  type 
) [static]

Definition at line 266 of file file.c.

References ext, and strsep().

Referenced by ast_filehelper(), ast_readfile(), and ast_writefile().

00267 {
00268    char tmp[256];
00269    char *stringp = tmp, *ext;
00270 
00271    ast_copy_string(tmp, exts, sizeof(tmp));
00272    while ((ext = strsep(&stringp, "|"))) {
00273       if (!strcmp(ext, type))
00274          return 1;
00275    }
00276 
00277    return 0;
00278 }

static int fileexists_core ( const char *  filename,
const char *  fmt,
const char *  preflang,
char *  buf,
int  buflen 
) [static]

helper routine to locate a file with a given format and language preference. Try preflang, preflang with stripped '_' suffix, or NULL. In the standard asterisk, language goes just before the last component. In an alternative configuration, the language should be a prefix to the actual filename.

The last parameter(s) point to a buffer of sufficient size, which on success is filled with the matching filename.

Definition at line 474 of file file.c.

References ACTION_EXISTS, ast_filehelper(), ast_log(), LOG_WARNING, and offset.

Referenced by ast_fileexists(), ast_openstream_full(), and ast_openvstream().

00476 {
00477    int res = -1;
00478    int langlen;   /* length of language string */
00479    const char *c = strrchr(filename, '/');
00480    int offset = c ? c - filename + 1 : 0; /* points right after the last '/' */
00481 
00482    if (preflang == NULL)
00483       preflang = "";
00484    langlen = strlen(preflang);
00485    
00486    if (buflen < langlen + strlen(filename) + 2) {
00487       ast_log(LOG_WARNING, "buffer too small\n");
00488       buf[0] = '\0'; /* set to empty */
00489       buf = alloca(langlen + strlen(filename) + 2);   /* room for everything */
00490    }
00491    if (buf == NULL)
00492       return 0;
00493    buf[0] = '\0';
00494    for (;;) {
00495       if (ast_language_is_prefix) { /* new layout */
00496          if (langlen) {
00497             strcpy(buf, preflang);
00498             buf[langlen] = '/';
00499             strcpy(buf + langlen + 1, filename);
00500          } else
00501             strcpy(buf, filename);  /* first copy the full string */
00502       } else { /* old layout */
00503          strcpy(buf, filename);  /* first copy the full string */
00504          if (langlen) {
00505             /* insert the language and suffix if needed */
00506             strcpy(buf + offset, preflang);
00507             sprintf(buf + offset + langlen, "/%s", filename + offset);
00508          }
00509       }
00510       res = ast_filehelper(buf, NULL, fmt, ACTION_EXISTS);
00511       if (res > 0)      /* found format */
00512          break;
00513       if (langlen == 0) /* no more formats */
00514          break;
00515       if (preflang[langlen] == '_') /* we are on the local suffix */
00516          langlen = 0;   /* try again with no language */
00517       else
00518          langlen = (c = strchr(preflang, '_')) ? c - preflang : 0;
00519    }
00520    return res;
00521 }

static int fn_wrapper ( struct ast_filestream s,
const char *  comment,
enum wrap_fn  mode 
) [static]

Definition at line 304 of file file.c.

References ast_log(), ast_module_ref(), f, LOG_WARNING, ast_format::module, ast_format::name, ast_format::open, ast_format::rewrite, s, and WRAP_OPEN.

Referenced by open_wrapper(), and rewrite_wrapper().

00305 {
00306    struct ast_format *f = s->fmt;
00307    int ret = -1;
00308 
00309    if (mode == WRAP_OPEN && f->open && f->open(s))
00310                 ast_log(LOG_WARNING, "Unable to open format %s\n", f->name);
00311    else if (mode == WRAP_REWRITE && f->rewrite && f->rewrite(s, comment))
00312                 ast_log(LOG_WARNING, "Unable to rewrite format %s\n", f->name);
00313    else {
00314       /* preliminary checks succeed. update usecount */
00315       ast_module_ref(f->module);
00316       ret = 0;
00317    }
00318         return ret;
00319 }

static struct ast_filestream* get_filestream ( struct ast_format fmt,
FILE *  bfile 
) [static]

Definition at line 280 of file file.c.

References ast_calloc, fmt, and s.

Referenced by ast_filehelper(), ast_readfile(), and ast_writefile().

00281 {
00282    struct ast_filestream *s;
00283 
00284    int l = sizeof(*s) + fmt->buf_size + fmt->desc_size;  /* total allocation size */
00285    if ( (s = ast_calloc(1, l)) == NULL)
00286       return NULL;
00287    s->fmt = fmt;
00288    s->f = bfile;
00289 
00290    if (fmt->desc_size)
00291       s->private = ((char *)(s+1)) + fmt->buf_size;
00292    if (fmt->buf_size)
00293       s->buf = (char *)(s+1);
00294    s->fr.src = fmt->name;
00295    return s;
00296 }

static int open_wrapper ( struct ast_filestream s  )  [static]

Definition at line 326 of file file.c.

References fn_wrapper(), s, and WRAP_OPEN.

Referenced by ast_filehelper(), and ast_readfile().

00327 {
00328    return fn_wrapper(s, NULL, WRAP_OPEN);
00329 }

static int rewrite_wrapper ( struct ast_filestream s,
const char *  comment 
) [static]

Definition at line 321 of file file.c.

References fn_wrapper(), and s.

Referenced by ast_writefile().

00322 {
00323    return fn_wrapper(s, comment, WRAP_REWRITE);
00324 }

static int show_file_formats ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 1140 of file file.c.

References ast_cli(), ast_getformatname(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_format::exts, f, ast_format::format, FORMAT, FORMAT2, ast_format::name, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01141 {
01142 #define FORMAT "%-10s %-10s %-20s\n"
01143 #define FORMAT2 "%-10s %-10s %-20s\n"
01144    struct ast_format *f;
01145    int count_fmt = 0;
01146 
01147    if (argc != 4)
01148       return RESULT_SHOWUSAGE;
01149    ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
01150 
01151    AST_RWLIST_RDLOCK(&formats);
01152    AST_RWLIST_TRAVERSE(&formats, f, list) {
01153       ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01154       count_fmt++;
01155    }
01156    AST_RWLIST_UNLOCK(&formats);
01157    ast_cli(fd, "%d file formats registered.\n", count_fmt);
01158    return RESULT_SUCCESS;
01159 #undef FORMAT
01160 #undef FORMAT2
01161 }

static int show_file_formats_deprecated ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 1163 of file file.c.

References ast_cli(), ast_getformatname(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_format::exts, f, ast_format::format, FORMAT, FORMAT2, LOG_WARNING, ast_format::name, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01164 {
01165 #define FORMAT "%-10s %-10s %-20s\n"
01166 #define FORMAT2 "%-10s %-10s %-20s\n"
01167    struct ast_format *f;
01168    int count_fmt = 0;
01169    
01170    if (argc != 3)
01171       return RESULT_SHOWUSAGE;
01172    ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
01173    
01174    if (AST_LIST_LOCK(&formats)) {
01175       ast_log(LOG_WARNING, "Unable to lock format list\n");
01176       return -1;
01177    }
01178    
01179    AST_LIST_TRAVERSE(&formats, f, list) {
01180       ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01181       count_fmt++;
01182    }
01183    AST_LIST_UNLOCK(&formats);
01184    ast_cli(fd, "%d file formats registered.\n", count_fmt);
01185    return RESULT_SUCCESS;
01186 #undef FORMAT
01187 #undef FORMAT2
01188 }

static int waitstream_core ( struct ast_channel c,
const char *  breakon,
const char *  forward,
const char *  rewind,
int  skip_ms,
int  audiofd,
int  cmdfd,
const char *  context 
) [static]

the core of all waitstream() functions

Definition at line 981 of file file.c.

References ast_channel::_softhangup, ast_clear_flag, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_exists_extension(), AST_FLAG_END_DTMF_ONLY, AST_FRAME_CONTROL, AST_FRAME_DTMF_END, AST_FRAME_VOICE, ast_frfree(), ast_log(), ast_read(), ast_sched_runq(), ast_sched_wait(), ast_set_flag, ast_stopstream(), ast_stream_fastforward(), ast_stream_rewind(), ast_waitfor(), ast_waitfor_nandfds(), ast_channel::cid, ast_callerid::cid_num, ast_frame::data, ast_frame::datalen, exten, ast_frame::frametype, LOG_WARNING, ast_channel::sched, ast_channel::stream, and ast_frame::subclass.

Referenced by ast_waitstream(), ast_waitstream_exten(), ast_waitstream_fr(), and ast_waitstream_full().

00984 {
00985    if (!breakon)
00986       breakon = "";
00987    if (!forward)
00988       forward = "";
00989    if (!rewind)
00990       rewind = "";
00991 
00992    /* Switch the channel to end DTMF frame only. waitstream_core doesn't care about the start of DTMF. */
00993    ast_set_flag(c, AST_FLAG_END_DTMF_ONLY);
00994    
00995    while (c->stream) {
00996       int res;
00997       int ms = ast_sched_wait(c->sched);
00998       if (ms < 0 && !c->timingfunc) {
00999          ast_stopstream(c);
01000          break;
01001       }
01002       if (ms < 0)
01003          ms = 1000;
01004       if (cmdfd < 0) {
01005          res = ast_waitfor(c, ms);
01006          if (res < 0) {
01007             ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
01008             ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01009             return res;
01010          }
01011       } else {
01012          int outfd;
01013          struct ast_channel *rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
01014          if (!rchan && (outfd < 0) && (ms)) {
01015             /* Continue */
01016             if (errno == EINTR)
01017                continue;
01018             ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
01019             ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01020             return -1;
01021          } else if (outfd > -1) { /* this requires cmdfd set */
01022             /* The FD we were watching has something waiting */
01023             ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01024             return 1;
01025          }
01026          /* if rchan is set, it is 'c' */
01027          res = rchan ? 1 : 0; /* map into 'res' values */
01028       }
01029       if (res > 0) {
01030          struct ast_frame *fr = ast_read(c);
01031          if (!fr) {
01032             ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01033             return -1;
01034          }
01035          switch(fr->frametype) {
01036          case AST_FRAME_DTMF_END:
01037             if (context) {
01038                const char exten[2] = { fr->subclass, '\0' };
01039                if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
01040                   res = fr->subclass;
01041                   ast_frfree(fr);
01042                   ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01043                   return res;
01044                }
01045             } else {
01046                res = fr->subclass;
01047                if (strchr(forward,res)) {
01048                   ast_stream_fastforward(c->stream, skip_ms);
01049                } else if (strchr(rewind,res)) {
01050                   ast_stream_rewind(c->stream, skip_ms);
01051                } else if (strchr(breakon, res)) {
01052                   ast_frfree(fr);
01053                   ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01054                   return res;
01055                }              
01056             }
01057             break;
01058          case AST_FRAME_CONTROL:
01059             switch(fr->subclass) {
01060             case AST_CONTROL_HANGUP:
01061             case AST_CONTROL_BUSY:
01062             case AST_CONTROL_CONGESTION:
01063                ast_frfree(fr);
01064                ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01065                return -1;
01066             case AST_CONTROL_RINGING:
01067             case AST_CONTROL_ANSWER:
01068             case AST_CONTROL_VIDUPDATE:
01069             case AST_CONTROL_HOLD:
01070             case AST_CONTROL_UNHOLD:
01071                /* Unimportant */
01072                break;
01073             default:
01074                ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01075             }
01076             break;
01077          case AST_FRAME_VOICE:
01078             /* Write audio if appropriate */
01079             if (audiofd > -1)
01080                write(audiofd, fr->data, fr->datalen);
01081          default:
01082             /* Ignore all others */
01083             break;
01084          }
01085          ast_frfree(fr);
01086       }
01087       ast_sched_runq(c->sched);
01088    }
01089 
01090    ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01091 
01092    return (c->_softhangup ? -1 : 0);
01093 }


Variable Documentation

int ast_language_is_prefix = 1

Definition at line 64 of file file.c.

struct ast_cli_entry cli_file[]

Initial value:

 {
   { { "core", "show", "file", "formats" },
   show_file_formats, "Displays file formats",
   show_file_formats_usage, NULL, &cli_show_file_formats_deprecated },
}

Definition at line 1199 of file file.c.

Referenced by ast_file_init().

struct ast_cli_entry cli_show_file_formats_deprecated

Initial value:

 {
   { "show", "file", "formats" },
   show_file_formats_deprecated, NULL,
   NULL }

Definition at line 1194 of file file.c.

char show_file_formats_usage[]

Initial value:

 
"Usage: core show file formats\n"
"       Displays currently registered file formats (if any)\n"

Definition at line 1190 of file file.c.


Generated on Fri Aug 24 02:25:48 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1