Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:48:09 2009

## Asterisk developer's documentation

# app_mp3.c File Reference

Silly application to play an MP3 file -- uses mpg123. More...

`#include <string.h>`
`#include <stdio.h>`
`#include <signal.h>`
`#include <stdlib.h>`
`#include <unistd.h>`
`#include <fcntl.h>`
`#include <sys/time.h>`
`#include "asterisk.h"`
`#include "asterisk/lock.h"`
`#include "asterisk/file.h"`
`#include "asterisk/logger.h"`
`#include "asterisk/channel.h"`
`#include "asterisk/frame.h"`
`#include "asterisk/pbx.h"`
`#include "asterisk/module.h"`
`#include "asterisk/translate.h"`
`#include "asterisk/options.h"`

Include dependency graph for app_mp3.c:

Go to the source code of this file.

## Defines

#define | LOCAL_MPG_123 "/usr/local/bin/mpg123"
#define | MPG_123 "/usr/bin/mpg123"

## Functions

char * | description (void)
| Provides a description of the module.
char * | key ()
| Returns the ASTERISK_GPL_KEY.
int | load_module (void)
| Initialize the module.
static int | mp3_exec (struct ast_channel *chan, void *data)
static int | mp3play (char *filename, int fd)
static int | timed_read (int fd, void *data, int datalen, int timeout)
int | unload_module (void)
| Cleanup all module structures, sockets, etc.
int | usecount (void)
| Provides a usecount.

## Variables

static char * | app = "MP3Player"
static char * | descrip
| LOCAL_USER_DECL
| STANDARD_LOCAL_USER
static char * | synopsis = "Play an MP3 file or stream"
static char * | tdesc = "Silly MP3 Application"

## Detailed Description

Silly application to play an MP3 file -- uses mpg123.

Definition in file app_mp3.c.

## Define Documentation

#define LOCAL_MPG_123 "/usr/local/bin/mpg123"

Definition at line 48 of file app_mp3.c.

Referenced by mp3play(), and spawn_mp3().

#define MPG_123 "/usr/bin/mpg123"

Definition at line 49 of file app_mp3.c.

Referenced by mp3play(), and spawn_mp3().

## Function Documentation

char* description | ( | void |  | ) |

Provides a description of the module.

Returns:
  a short description of your module

Definition at line 258 of file app_mp3.c.

    00259 {
    00260    return tdesc;
    00261 }

char* key | ( | void |  | ) |

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

     char *key(void) {
             return ASTERISK_GPL_KEY;
     }

Returns:
  ASTERISK_GPL_KEY

Definition at line 270 of file app_mp3.c.

References ASTERISK_GPL_KEY.

    00271 {
    00272    return ASTERISK_GPL_KEY;
    00273 }

int load_module | ( | void |  | ) |

Initialize the module.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
  This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
  int Always 0.

TE STUFF END

Definition at line 253 of file app_mp3.c.

References ast_register_application(), and mp3_exec().

    00254 {
    00255    return ast_register_application(app, mp3_exec, synopsis, descrip);
    00256 }

static int mp3_exec | ( | struct ast_channel * | chan,
|  | void * | data |
| ) |  |  | `[static]`

Definition at line 128 of file app_mp3.c.

References AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree(), AST_FRIENDLY_OFFSET, ast_log(), ast_read(), ast_set_write_format(), ast_stopstream(), ast_strlen_zero(), ast_tvadd(), ast_waitfor(), ast_write(), ast_frame::frametype, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_DEBUG, LOG_WARNING, mp3play(), offset, timed_read(), and ast_channel::writeformat.

Referenced by load_module().

    00129 {
    00130    int res=0;
    00131    struct localuser *u;
    00132    int fds[2];
    00133    int ms = -1;
    00134    int pid = -1;
    00135    int owriteformat;
    00136    int timeout = 2000;
    00137    struct timeval next;
    00138    struct ast_frame *f;
    00139    struct myframe {
    00140       struct ast_frame f;
    00141       char offset[AST_FRIENDLY_OFFSET];
    00142       short frdata[160];
    00143    } myf;
    00144
    00145    if (ast_strlen_zero(data)) {
    00146       ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
    00147       return -1;
    00148    }
    00149
    00150    LOCAL_USER_ADD(u);
    00151
    00152    if (pipe(fds)) {
    00153       ast_log(LOG_WARNING, "Unable to create pipe\n");
    00154       LOCAL_USER_REMOVE(u);
    00155       return -1;
    00156    }
    00157
    00158    ast_stopstream(chan);
    00159
    00160    owriteformat = chan->writeformat;
    00161    res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
    00162    if (res < 0) {
    00163       ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
    00164       LOCAL_USER_REMOVE(u);
    00165       return -1;
    00166    }
    00167
    00168    res = mp3play((char *)data, fds[1]);
    00169    if (!strncasecmp((char *)data, "http://", 7)) {
    00170       timeout = 10000;
    00171    }
    00172    /* Wait 1000 ms first */
    00173    next = ast_tvnow();
    00174    next.tv_sec += 1;
    00175    if (res >= 0) {
    00176       pid = res;
    00177       /* Order is important -- there's almost always going to be mp3...  we want to prioritize the
    00178          user */
    00179       for (;;) {
    00180          ms = ast_tvdiff_ms(next, ast_tvnow());
    00181          if (ms <= 0) {
    00182             res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
    00183             if (res > 0) {
    00184                myf.f.frametype = AST_FRAME_VOICE;
    00185                myf.f.subclass = AST_FORMAT_SLINEAR;
    00186                myf.f.datalen = res;
    00187                myf.f.samples = res / 2;
    00188                myf.f.mallocd = 0;
    00189                myf.f.offset = AST_FRIENDLY_OFFSET;
    00190                myf.f.src = __PRETTY_FUNCTION__;
    00191                myf.f.delivery.tv_sec = 0;
    00192                myf.f.delivery.tv_usec = 0;
    00193                myf.f.data = myf.frdata;
    00194                if (ast_write(chan, &myf.f) < 0) {
    00195                   res = -1;
    00196                   break;
    00197                }
    00198             } else {
    00199                ast_log(LOG_DEBUG, "No more mp3\n");
    00200                res = 0;
    00201                break;
    00202             }
    00203             next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
    00204          } else {
    00205             ms = ast_waitfor(chan, ms);
    00206             if (ms < 0) {
    00207                ast_log(LOG_DEBUG, "Hangup detected\n");
    00208                res = -1;
    00209                break;
    00210             }
    00211             if (ms) {
    00212                f = ast_read(chan);
    00213                if (!f) {
    00214                   ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
    00215                   res = -1;
    00216                   break;
    00217                }
    00218                if (f->frametype == AST_FRAME_DTMF) {
    00219                   ast_log(LOG_DEBUG, "User pressed a key\n");
    00220                   ast_frfree(f);
    00221                   res = 0;
    00222                   break;
    00223                }
    00224                ast_frfree(f);
    00225             }
    00226          }
    00227       }
    00228    }
    00229    close(fds[0]);
    00230    close(fds[1]);
    00231
    00232    if (pid > -1)
    00233       kill(pid, SIGKILL);
    00234    if (!res && owriteformat)
    00235       ast_set_write_format(chan, owriteformat);
    00236
    00237    LOCAL_USER_REMOVE(u);
    00238
    00239    return res;
    00240 }

static int mp3play | ( | char * | filename,
|  | int | fd |
| ) |  |  | `[static]`

Definition at line 66 of file app_mp3.c.

References ast_log(), ast_set_priority(), LOCAL_MPG_123, LOG_WARNING, MPG_123, and option_highpriority.

Referenced by mp3_exec().

    00067 {
    00068    int res;
    00069    int x;
    00070    sigset_t fullset, oldset;
    00071
    00072    sigfillset(&fullset);
    00073    pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
    00074
    00075    res = fork();
    00076    if (res < 0)
    00077       ast_log(LOG_WARNING, "Fork failed\n");
    00078    if (res) {
    00079       pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    00080       return res;
    00081    }
    00082    if (option_highpriority)
    00083       ast_set_priority(0);
    00084    signal(SIGPIPE, SIG_DFL);
    00085    pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
    00086
    00087    dup2(fd, STDOUT_FILENO);
    00088    for (x=STDERR_FILENO + 1;x<256;x++) {
    00089       if (x != STDOUT_FILENO)
    00090          close(x);
    00091    }
    00092    /* Execute mpg123, but buffer if it's a net connection */
    00093    if (!strncasecmp(filename, "http://", 7)) {
    00094       /* Most commonly installed in /usr/local/bin */
    00095        execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
    00096       /* But many places has it in /usr/bin */
    00097        execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
    00098       /* As a last-ditch effort, try to use PATH */
    00099        execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024",  "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
    00100    }
    00101    else {
    00102       /* Most commonly installed in /usr/local/bin */
    00103        execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
    00104       /* But many places has it in /usr/bin */
    00105        execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
    00106       /* As a last-ditch effort, try to use PATH */
    00107        execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
    00108    }
    00109    ast_log(LOG_WARNING, "Execute of mpg123 failed\n");
    00110    _exit(0);
    00111 }

static int timed_read | ( | int | fd,
|  | void * | data,
|  | int | datalen,
|  | int | timeout |
| ) |  |  | `[static]`

Definition at line 113 of file app_mp3.c.

References ast_log(), pollfd::events, pollfd::fd, LOG_NOTICE, poll(), and POLLIN.

Referenced by mp3_exec(), and NBScat_exec().

    00114 {
    00115    int res;
    00116    struct pollfd fds[1];
    00117    fds[0].fd = fd;
    00118    fds[0].events = POLLIN;
    00119    res = poll(fds, 1, timeout);
    00120    if (res < 1) {
    00121       ast_log(LOG_NOTICE, "Poll timed out/errored out with %d\n", res);
    00122       return -1;
    00123    }
    00124    return read(fd, data, datalen);
    00125
    00126 }

int unload_module | ( | void |  | ) |

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
  Zero on success, or non-zero on error.

Definition at line 242 of file app_mp3.c.

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

    00243 {
    00244    int res;
    00245
    00246    res = ast_unregister_application(app);
    00247
    00248    STANDARD_HANGUP_LOCALUSERS;
    00249
    00250    return res;
    00251 }

int usecount | ( | void |  | ) |

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
  The module's usecount.

Definition at line 263 of file app_mp3.c.

References STANDARD_USECOUNT.

    00264 {
    00265    int res;
    00266    STANDARD_USECOUNT(res);
    00267    return res;
    00268 }

## Variable Documentation

char* app = "MP3Player"`[static]`

Definition at line 53 of file app_mp3.c.

char* descrip`[static]`

Initial value:

    "  MP3Player(location) Executes mpg123 to play the given location,\n"
    "which typically would be a filename or a URL. User can exit by pressing\n"
    "any key on the dialpad, or by hanging up."

Definition at line 57 of file app_mp3.c.

LOCAL_USER_DECL

Definition at line 64 of file app_mp3.c.

STANDARD_LOCAL_USER

Definition at line 62 of file app_mp3.c.

char* synopsis = "Play an MP3 file or stream"`[static]`

Definition at line 55 of file app_mp3.c.

char* tdesc = "Silly MP3 Application"`[static]`

Definition at line 51 of file app_mp3.c.