Asterisk.org: Developer Documentation (28 Oct 2009)

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