Wed Oct 28 11:50:52 2009

Asterisk developer's documentation


app_ices.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  * 
00025  * \extref ICES - http://www.icecast.org/ices.php
00026  *
00027  * \ingroup applications
00028  */
00029  
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 135059 $")
00033 
00034 #include <signal.h>
00035 #include <fcntl.h>
00036 #include <sys/time.h>
00037 
00038 #include "asterisk/paths.h"   /* use ast_config_AST_CONFIG_DIR */
00039 #include "asterisk/lock.h"
00040 #include "asterisk/file.h"
00041 #include "asterisk/channel.h"
00042 #include "asterisk/frame.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/translate.h"
00046 #include "asterisk/app.h"
00047 
00048 #define path_BIN "/usr/bin/"
00049 #define path_LOCAL "/usr/local/bin/"
00050 
00051 static char *app = "ICES";
00052 
00053 static char *synopsis = "Encode and stream using 'ices'";
00054 
00055 static char *descrip = 
00056 "  ICES(config.xml) Streams to an icecast server using ices\n"
00057 "(available separately).  A configuration file must be supplied\n"
00058 "for ices (see contrib/asterisk-ices.xml). \n"
00059 "\n"
00060 "- ICES version 2 cient and server required.\n";
00061 
00062 
00063 static int icesencode(char *filename, int fd)
00064 {
00065    int res;
00066 
00067    res = ast_safe_fork(0);
00068    if (res < 0) 
00069       ast_log(LOG_WARNING, "Fork failed\n");
00070    if (res) {
00071       return res;
00072    }
00073 
00074    if (ast_opt_high_priority)
00075       ast_set_priority(0);
00076    dup2(fd, STDIN_FILENO);
00077    ast_close_fds_above_n(STDERR_FILENO);
00078 
00079    /* Most commonly installed in /usr/local/bin 
00080     * But many places has it in /usr/bin 
00081     * As a last-ditch effort, try to use PATH
00082     */
00083    execl(path_LOCAL "ices2", "ices", filename, SENTINEL);
00084    execl(path_BIN "ices2", "ices", filename, SENTINEL);
00085    execlp("ices2", "ices", filename, SENTINEL);
00086 
00087    ast_debug(1, "Couldn't find ices version 2, attempting to use ices version 1.");
00088 
00089    execl(path_LOCAL "ices", "ices", filename, SENTINEL);
00090    execl(path_BIN "ices", "ices", filename, SENTINEL);
00091    execlp("ices", "ices", filename, SENTINEL);
00092 
00093    ast_log(LOG_WARNING, "Execute of ices failed, could not find command.\n");
00094    close(fd);
00095    _exit(0);
00096 }
00097 
00098 static int ices_exec(struct ast_channel *chan, void *data)
00099 {
00100    int res = 0;
00101    int fds[2];
00102    int ms = -1;
00103    int pid = -1;
00104    int flags;
00105    int oreadformat;
00106    struct timeval last;
00107    struct ast_frame *f;
00108    char filename[256]="";
00109    char *c;
00110 
00111    if (ast_strlen_zero(data)) {
00112       ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
00113       return -1;
00114    }
00115    
00116    last = ast_tv(0, 0);
00117    
00118    if (pipe(fds)) {
00119       ast_log(LOG_WARNING, "Unable to create pipe\n");
00120       return -1;
00121    }
00122    flags = fcntl(fds[1], F_GETFL);
00123    fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
00124    
00125    ast_stopstream(chan);
00126 
00127    if (chan->_state != AST_STATE_UP)
00128       res = ast_answer(chan);
00129       
00130    if (res) {
00131       close(fds[0]);
00132       close(fds[1]);
00133       ast_log(LOG_WARNING, "Answer failed!\n");
00134       return -1;
00135    }
00136 
00137    oreadformat = chan->readformat;
00138    res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00139    if (res < 0) {
00140       close(fds[0]);
00141       close(fds[1]);
00142       ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
00143       return -1;
00144    }
00145    if (((char *)data)[0] == '/')
00146       ast_copy_string(filename, (char *) data, sizeof(filename));
00147    else
00148       snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_CONFIG_DIR, (char *)data);
00149    /* Placeholder for options */    
00150    c = strchr(filename, '|');
00151    if (c)
00152       *c = '\0';  
00153    res = icesencode(filename, fds[0]);
00154    if (res >= 0) {
00155       pid = res;
00156       for (;;) {
00157          /* Wait for audio, and stream */
00158          ms = ast_waitfor(chan, -1);
00159          if (ms < 0) {
00160             ast_debug(1, "Hangup detected\n");
00161             res = -1;
00162             break;
00163          }
00164          f = ast_read(chan);
00165          if (!f) {
00166             ast_debug(1, "Null frame == hangup() detected\n");
00167             res = -1;
00168             break;
00169          }
00170          if (f->frametype == AST_FRAME_VOICE) {
00171             res = write(fds[1], f->data.ptr, f->datalen);
00172             if (res < 0) {
00173                if (errno != EAGAIN) {
00174                   ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
00175                   res = -1;
00176                   ast_frfree(f);
00177                   break;
00178                }
00179             }
00180          }
00181          ast_frfree(f);
00182       }
00183    }
00184    close(fds[0]);
00185    close(fds[1]);
00186 
00187    if (pid > -1)
00188       kill(pid, SIGKILL);
00189    if (!res && oreadformat)
00190       ast_set_read_format(chan, oreadformat);
00191 
00192    return res;
00193 }
00194 
00195 static int unload_module(void)
00196 {
00197    return ast_unregister_application(app);
00198 }
00199 
00200 static int load_module(void)
00201 {
00202    return ast_register_application(app, ices_exec, synopsis, descrip);
00203 }
00204 
00205 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");

Generated on Wed Oct 28 11:50:52 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6