format_mp3.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Anthony Minessale <anthmct@yahoo.com>
00005  *
00006  * Derived from other asterisk sound formats by
00007  * Mark Spencer <markster@linux-support.net>
00008  *
00009  * Thanks to mpglib from http://www.mpg123.org/
00010  * and Chris Stenton [jacs@gnome.co.uk]
00011  * for coding the ability to play stereo and non-8khz files
00012 
00013  * See http://www.asterisk.org for more information about
00014  * the Asterisk project. Please do not directly contact
00015  * any of the maintainers of this project for assistance;
00016  * the project provides a web site, mailing lists and IRC
00017  * channels for your use.
00018  *
00019  * This program is free software, distributed under the terms of
00020  * the GNU General Public License Version 2. See the LICENSE file
00021  * at the top of the source tree.
00022  */
00023 
00024 /*!
00025  * \file
00026  * \brief MP3 Format Handler
00027  * \ingroup formats
00028  */
00029 
00030 /*** MODULEINFO
00031    <defaultenabled>no</defaultenabled>
00032    <support_level>extended</support_level>
00033  ***/
00034 
00035 #include "asterisk.h"
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
00038 
00039 #include "mp3/mpg123.h"
00040 #include "mp3/mpglib.h"
00041 
00042 #include "asterisk/module.h"
00043 #include "asterisk/mod_format.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/format_cache.h"
00046 
00047 #define MP3_BUFLEN 320
00048 #define MP3_SCACHE 16384
00049 #define MP3_DCACHE 8192
00050 
00051 struct mp3_private {
00052    /*! state for the mp3 decoder */
00053    struct mpstr mp;
00054    /*! buffer to hold mp3 data after read from disk */
00055    char sbuf[MP3_SCACHE];
00056    /*! buffer for slinear audio after being decoded out of sbuf */
00057    char dbuf[MP3_DCACHE];
00058    /*! how much data has been written to the output buffer in the ast_filestream */
00059    int buflen;
00060    /*! how much data has been written to sbuf */
00061    int sbuflen;
00062    /*! how much data is left to be read out of dbuf, starting at dbufoffset */
00063    int dbuflen;
00064    /*! current offset for reading data out of dbuf */
00065    int dbufoffset;
00066    int offset;
00067    long seek;
00068 };
00069 
00070 static const char name[] = "mp3";
00071 
00072 #define BLOCKSIZE 160
00073 #define OUTSCALE 4096
00074 
00075 #define GAIN -4      /* 2^GAIN is the multiple to increase the volume by */
00076 
00077 #if __BYTE_ORDER == __LITTLE_ENDIAN
00078 #define htoll(b) (b)
00079 #define htols(b) (b)
00080 #define ltohl(b) (b)
00081 #define ltohs(b) (b)
00082 #else
00083 #if __BYTE_ORDER == __BIG_ENDIAN
00084 #define htoll(b)  \
00085           (((((b)      ) & 0xFF) << 24) | \
00086           ((((b) >>  8) & 0xFF) << 16) | \
00087          ((((b) >> 16) & 0xFF) <<  8) | \
00088          ((((b) >> 24) & 0xFF)      ))
00089 #define htols(b) \
00090           (((((b)      ) & 0xFF) << 8) | \
00091          ((((b) >> 8) & 0xFF)      ))
00092 #define ltohl(b) htoll(b)
00093 #define ltohs(b) htols(b)
00094 #else
00095 #error "Endianess not defined"
00096 #endif
00097 #endif
00098 
00099 
00100 static int mp3_open(struct ast_filestream *s)
00101 {
00102    struct mp3_private *p = s->_private;
00103    InitMP3(&p->mp, OUTSCALE);
00104    return 0;
00105 }
00106 
00107 
00108 static void mp3_close(struct ast_filestream *s)
00109 {
00110    struct mp3_private *p = s->_private;
00111 
00112    ExitMP3(&p->mp);
00113    return;
00114 }
00115 
00116 static int mp3_squeue(struct ast_filestream *s)
00117 {
00118    struct mp3_private *p = s->_private;
00119    int res=0;
00120 
00121    res = ftell(s->f);
00122    p->sbuflen = fread(p->sbuf, 1, MP3_SCACHE, s->f);
00123    if(p->sbuflen < 0) {
00124       ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", p->sbuflen, strerror(errno));
00125       return -1;
00126    }
00127    res = decodeMP3(&p->mp,p->sbuf,p->sbuflen,p->dbuf,MP3_DCACHE,&p->dbuflen);
00128    if(res != MP3_OK)
00129       return -1;
00130    p->sbuflen -= p->dbuflen;
00131    p->dbufoffset = 0;
00132    return 0;
00133 }
00134 
00135 static int mp3_dqueue(struct ast_filestream *s)
00136 {
00137    struct mp3_private *p = s->_private;
00138    int res=0;
00139 
00140    if((res = decodeMP3(&p->mp,NULL,0,p->dbuf,MP3_DCACHE,&p->dbuflen)) == MP3_OK) {
00141       p->sbuflen -= p->dbuflen;
00142       p->dbufoffset = 0;
00143    }
00144    return res;
00145 }
00146 
00147 static int mp3_queue(struct ast_filestream *s)
00148 {
00149    struct mp3_private *p = s->_private;
00150    int res = 0, bytes = 0;
00151 
00152    if(p->seek) {
00153       ExitMP3(&p->mp);
00154       InitMP3(&p->mp, OUTSCALE);
00155       fseek(s->f, 0, SEEK_SET);
00156       p->sbuflen = p->dbuflen = p->offset = 0;
00157       while(p->offset < p->seek) {
00158          if(mp3_squeue(s))
00159             return -1;
00160          while(p->offset < p->seek && ((res = mp3_dqueue(s))) == MP3_OK) {
00161             for(bytes = 0 ; bytes < p->dbuflen ; bytes++) {
00162                p->dbufoffset++;
00163                p->offset++;
00164                if(p->offset >= p->seek)
00165                   break;
00166             }
00167          }
00168          if(res == MP3_ERR)
00169             return -1;
00170       }
00171 
00172       p->seek = 0;
00173       return 0;
00174    }
00175    if(p->dbuflen == 0) {
00176       if(p->sbuflen) {
00177          res = mp3_dqueue(s);
00178          if(res == MP3_ERR)
00179             return -1;
00180       }
00181       if(! p->sbuflen || res != MP3_OK) {
00182          if(mp3_squeue(s))
00183             return -1;
00184       }
00185 
00186    }
00187 
00188    return 0;
00189 }
00190 
00191 static struct ast_frame *mp3_read(struct ast_filestream *s, int *whennext)
00192 {
00193 
00194    struct mp3_private *p = s->_private;
00195    int delay =0;
00196    int save=0;
00197 
00198    /* Pre-populate the buffer that holds audio to be returned (dbuf) */
00199    if (mp3_queue(s)) {
00200       return NULL;
00201    }
00202 
00203    if (p->dbuflen) {
00204       /* Read out what's waiting in dbuf */
00205       for (p->buflen = 0; p->buflen < MP3_BUFLEN && p->buflen < p->dbuflen; p->buflen++) {
00206          s->buf[p->buflen + AST_FRIENDLY_OFFSET] = p->dbuf[p->buflen + p->dbufoffset];
00207       }
00208       p->dbufoffset += p->buflen;
00209       p->dbuflen -= p->buflen;
00210    }
00211 
00212    if (p->buflen < MP3_BUFLEN) {
00213       /* dbuf didn't have enough, so reset dbuf, fill it back up and continue */
00214       p->dbuflen = p->dbufoffset = 0;
00215 
00216       if (mp3_queue(s)) {
00217          return NULL;
00218       }
00219 
00220       /* Make sure dbuf has enough to complete this read attempt */
00221       if (p->dbuflen >= (MP3_BUFLEN - p->buflen)) {
00222          for (save = p->buflen; p->buflen < MP3_BUFLEN; p->buflen++) {
00223             s->buf[p->buflen + AST_FRIENDLY_OFFSET] = p->dbuf[(p->buflen - save) + p->dbufoffset];
00224          }
00225          p->dbufoffset += (MP3_BUFLEN - save);
00226          p->dbuflen -= (MP3_BUFLEN - save);
00227       }
00228 
00229    }
00230 
00231    p->offset += p->buflen;
00232    delay = p->buflen / 2;
00233    AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, p->buflen);
00234    s->fr.samples = delay;
00235    *whennext = delay;
00236    return &s->fr;
00237 }
00238 
00239 
00240 static int mp3_write(struct ast_filestream *fs, struct ast_frame *f)
00241 {
00242    ast_log(LOG_ERROR,"I Can't write MP3 only read them.\n");
00243    return -1;
00244 
00245 }
00246 
00247 
00248 static int mp3_seek(struct ast_filestream *s, off_t sample_offset, int whence)
00249 {
00250    struct mp3_private *p = s->_private;
00251    off_t min,max,cur;
00252    long offset=0,samples;
00253    samples = sample_offset * 2;
00254 
00255    min = 0;
00256    fseek(s->f, 0, SEEK_END);
00257    max = ftell(s->f) * 100;
00258    cur = p->offset;
00259 
00260    if (whence == SEEK_SET)
00261       offset = samples + min;
00262    else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
00263       offset = samples + cur;
00264    else if (whence == SEEK_END)
00265       offset = max - samples;
00266    if (whence != SEEK_FORCECUR) {
00267       offset = (offset > max)?max:offset;
00268    }
00269 
00270    p->seek = offset;
00271    return fseek(s->f, offset, SEEK_SET);
00272 
00273 }
00274 
00275 static int mp3_rewrite(struct ast_filestream *s, const char *comment)
00276 {
00277    ast_log(LOG_ERROR,"I Can't write MP3 only read them.\n");
00278    return -1;
00279 }
00280 
00281 static int mp3_trunc(struct ast_filestream *s)
00282 {
00283 
00284    ast_log(LOG_ERROR,"I Can't write MP3 only read them.\n");
00285    return -1;
00286 }
00287 
00288 static off_t mp3_tell(struct ast_filestream *s)
00289 {
00290    struct mp3_private *p = s->_private;
00291 
00292    return p->offset/2;
00293 }
00294 
00295 static char *mp3_getcomment(struct ast_filestream *s)
00296 {
00297    return NULL;
00298 }
00299 
00300 static struct ast_format_def mp3_f = {
00301    .name = "mp3",
00302    .exts = "mp3",
00303    .open = mp3_open,
00304    .write = mp3_write,
00305    .rewrite = mp3_rewrite,
00306    .seek =  mp3_seek,
00307    .trunc = mp3_trunc,
00308    .tell =  mp3_tell,
00309    .read =  mp3_read,
00310    .close = mp3_close,
00311    .getcomment = mp3_getcomment,
00312    .buf_size = MP3_BUFLEN + AST_FRIENDLY_OFFSET,
00313    .desc_size = sizeof(struct mp3_private),
00314 };
00315 
00316 
00317 static int load_module(void)
00318 {
00319    mp3_f.format = ast_format_slin;
00320    InitMP3Constants();
00321    return ast_format_def_register(&mp3_f);
00322 }
00323 
00324 static int unload_module(void)
00325 {
00326    return ast_format_def_unregister(name);
00327 }
00328 
00329 AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "MP3 format [Any rate but 8000hz mono is optimal]");
00330 

Generated on Thu Apr 16 06:27:34 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6