Thu Jul 9 13:40:18 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 /*** MODULEINFO
00031    <depend>working_fork</depend>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 172503 $")
00037 
00038 #include <signal.h>
00039 #include <fcntl.h>
00040 #include <sys/time.h>
00041 #ifdef HAVE_CAP
00042 #include <sys/capability.h>
00043 #endif /* HAVE_CAP */
00044 
00045 #include "asterisk/paths.h"   /* use ast_config_AST_CONFIG_DIR */
00046 #include "asterisk/lock.h"
00047 #include "asterisk/file.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/frame.h"
00050 #include "asterisk/pbx.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/translate.h"
00053 
00054 #define path_BIN "/usr/bin/"
00055 #define path_LOCAL "/usr/local/bin/"
00056 
00057 static char *app = "ICES";
00058 
00059 static char *synopsis = "Encode and stream using 'ices'";
00060 
00061 static char *descrip = 
00062 "  ICES(config.xml) Streams to an icecast server using ices\n"
00063 "(available separately).  A configuration file must be supplied\n"
00064 "for ices (see contrib/asterisk-ices.xml). \n"
00065 "\n"
00066 "- ICES version 2 cient and server required.\n";
00067 
00068 
00069 static int icesencode(char *filename, int fd)
00070 {
00071    int res;
00072    int x;
00073    sigset_t fullset, oldset;
00074 #ifdef HAVE_CAP
00075    cap_t cap;
00076 #endif
00077 
00078    sigfillset(&fullset);
00079    pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
00080 
00081    res = fork();
00082    if (res < 0) 
00083       ast_log(LOG_WARNING, "Fork failed\n");
00084    if (res) {
00085       pthread_sigmask(SIG_SETMASK, &oldset, NULL);
00086       return res;
00087    }
00088 
00089    /* Stop ignoring PIPE */
00090    signal(SIGPIPE, SIG_DFL);
00091    pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
00092 
00093 #ifdef HAVE_CAP
00094    cap = cap_from_text("cap_net_admin-eip");
00095 
00096    if (cap_set_proc(cap)) {
00097       /* Careful with order! Logging cannot happen after we close FDs */
00098       ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
00099    }
00100    cap_free(cap);
00101 #endif
00102 
00103    if (ast_opt_high_priority)
00104       ast_set_priority(0);
00105    dup2(fd, STDIN_FILENO);
00106    for (x=STDERR_FILENO + 1;x<1024;x++) {
00107       if ((x != STDIN_FILENO) && (x != STDOUT_FILENO))
00108          close(x);
00109    }
00110 
00111    /* Most commonly installed in /usr/local/bin 
00112     * But many places has it in /usr/bin 
00113     * As a last-ditch effort, try to use PATH
00114     */
00115    execl(path_LOCAL "ices2", "ices", filename, (char *)NULL);
00116    execl(path_BIN "ices2", "ices", filename, (char *)NULL);
00117    execlp("ices2", "ices", filename, (char *)NULL);
00118 
00119    ast_debug(1, "Couldn't find ices version 2, attempting to use ices version 1.");
00120 
00121    execl(path_LOCAL "ices", "ices", filename, (char *)NULL);
00122    execl(path_BIN "ices", "ices", filename, (char *)NULL);
00123    execlp("ices", "ices", filename, (char *)NULL);
00124 
00125    ast_log(LOG_WARNING, "Execute of ices failed, could not find command.\n");
00126    close(fd);
00127    _exit(0);
00128 }
00129 
00130 static int ices_exec(struct ast_channel *chan, void *data)
00131 {
00132    int res = 0;
00133    int fds[2];
00134    int ms = -1;
00135    int pid = -1;
00136    int flags;
00137    int oreadformat;
00138    struct timeval last;
00139    struct ast_frame *f;
00140    char filename[256]="";
00141    char *c;
00142 
00143    if (ast_strlen_zero(data)) {
00144       ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
00145       return -1;
00146    }
00147    
00148    last = ast_tv(0, 0);
00149    
00150    if (pipe(fds)) {
00151       ast_log(LOG_WARNING, "Unable to create pipe\n");
00152       return -1;
00153    }
00154    flags = fcntl(fds[1], F_GETFL);
00155    fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
00156    
00157    ast_stopstream(chan);
00158 
00159    if (chan->_state != AST_STATE_UP)
00160       res = ast_answer(chan);
00161       
00162    if (res) {
00163       close(fds[0]);
00164       close(fds[1]);
00165       ast_log(LOG_WARNING, "Answer failed!\n");
00166       return -1;
00167    }
00168 
00169    oreadformat = chan->readformat;
00170    res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00171    if (res < 0) {
00172       close(fds[0]);
00173       close(fds[1]);
00174       ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
00175       return -1;
00176    }
00177    if (((char *)data)[0] == '/')
00178       ast_copy_string(filename, (char *) data, sizeof(filename));
00179    else
00180       snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_CONFIG_DIR, (char *)data);
00181    /* Placeholder for options */    
00182    c = strchr(filename, '|');
00183    if (c)
00184       *c = '\0';  
00185    res = icesencode(filename, fds[0]);
00186    if (res >= 0) {
00187       pid = res;
00188       for (;;) {
00189          /* Wait for audio, and stream */
00190          ms = ast_waitfor(chan, -1);
00191          if (ms < 0) {
00192             ast_debug(1, "Hangup detected\n");
00193             res = -1;
00194             break;
00195          }
00196          f = ast_read(chan);
00197          if (!f) {
00198             ast_debug(1, "Null frame == hangup() detected\n");
00199             res = -1;
00200             break;
00201          }
00202          if (f->frametype == AST_FRAME_VOICE) {
00203             res = write(fds[1], f->data, f->datalen);
00204             if (res < 0) {
00205                if (errno != EAGAIN) {
00206                   ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
00207                   res = -1;
00208                   ast_frfree(f);
00209                   break;
00210                }
00211             }
00212          }
00213          ast_frfree(f);
00214       }
00215    }
00216    close(fds[0]);
00217    close(fds[1]);
00218    
00219    if (pid > -1)
00220       kill(pid, SIGKILL);
00221    if (!res && oreadformat)
00222       ast_set_read_format(chan, oreadformat);
00223 
00224    return res;
00225 }
00226 
00227 static int unload_module(void)
00228 {
00229    return ast_unregister_application(app);
00230 }
00231 
00232 static int load_module(void)
00233 {
00234    return ast_register_application(app, ices_exec, synopsis, descrip);
00235 }
00236 
00237 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");

Generated on Thu Jul 9 13:40:18 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7