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

Generated on Wed Mar 4 19:57:58 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7