Sat Aug 6 00:39:20 2011

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

Generated on Sat Aug 6 00:39:20 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7