Mon Mar 31 07:38:02 2008

Asterisk developer's documentation


format_mp3.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * format_mp3.c
00005  * Anthony Minessale <anthmct@yahoo.com>
00006  *
00007  * Derived from other asterisk sound formats by
00008  * Mark Spencer <markster@linux-support.net>
00009  *
00010  * Thanks to mpglib from http://www.mpg123.org/
00011  * and Chris Stenton [jacs@gnome.co.uk]
00012  * for coding the ability to play stereo and non-8khz files
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License
00016  */
00017 
00018 #include <asterisk.h>
00019 
00020 #include "mpg123.h" 
00021 #include "mpglib.h" 
00022 #include <asterisk/lock.h>
00023 #include <asterisk/channel.h>
00024 #include <asterisk/file.h>
00025 #include <asterisk/logger.h>
00026 #include <asterisk/sched.h>
00027 #include <asterisk/module.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030 #include <stdlib.h>
00031 #include <sys/time.h>
00032 #include <stdio.h>
00033 #include <unistd.h>
00034 #include <errno.h>
00035 #include <string.h>
00036 #ifdef __linux__
00037 #include <endian.h>
00038 #else
00039 #include <machine/endian.h>
00040 #endif
00041 
00042 #define AST_MODULE "format_mp3"
00043 
00044 #define MP3_BUFLEN 320
00045 #define MP3_SCACHE 16384
00046 #define MP3_DCACHE 8192
00047 
00048 /* Based on format_wav.c */
00049 
00050 struct mp3_private {
00051    char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
00052    char empty;          /* Empty character */
00053    int lasttimeout;
00054    int maxlen;
00055    struct timeval last;
00056    struct mpstr mp;
00057    char sbuf[MP3_SCACHE];
00058    char dbuf[MP3_DCACHE];
00059    int buflen;
00060    int sbuflen;
00061    int dbuflen;
00062    int dbufoffset;
00063    int sbufoffset;
00064    int lastseek;
00065    int offset;
00066    long seek;
00067 };
00068 
00069 static char *name = "mp3";
00070 
00071 #define BLOCKSIZE 160
00072 #define OUTSCALE 4096
00073 
00074 #define GAIN -4      /* 2^GAIN is the multiple to increase the volume by */
00075 
00076 #if __BYTE_ORDER == __LITTLE_ENDIAN
00077 #define htoll(b) (b)
00078 #define htols(b) (b)
00079 #define ltohl(b) (b)
00080 #define ltohs(b) (b)
00081 #else
00082 #if __BYTE_ORDER == __BIG_ENDIAN
00083 #define htoll(b)  \
00084           (((((b)      ) & 0xFF) << 24) | \
00085           ((((b) >>  8) & 0xFF) << 16) | \
00086          ((((b) >> 16) & 0xFF) <<  8) | \
00087          ((((b) >> 24) & 0xFF)      ))
00088 #define htols(b) \
00089           (((((b)      ) & 0xFF) << 8) | \
00090          ((((b) >> 8) & 0xFF)      ))
00091 #define ltohl(b) htoll(b)
00092 #define ltohs(b) htols(b)
00093 #else
00094 #error "Endianess not defined"
00095 #endif
00096 #endif
00097 
00098 
00099 static int mp3_open(struct ast_filestream *s)
00100 {
00101    struct mp3_private *p = s->_private;
00102    
00103    InitMP3(&p->mp, OUTSCALE);
00104    p->dbuflen = 0;
00105    s->fr.data = s->buf;
00106    s->fr.frametype = AST_FRAME_VOICE;
00107    s->fr.subclass = AST_FORMAT_SLINEAR;
00108    /* datalen will vary for each frame */
00109    s->fr.src = name;
00110    s->fr.mallocd = 0;
00111    p->offset = 0;
00112    return 0;
00113 }
00114 
00115 
00116 static void mp3_close(struct ast_filestream *s)
00117 {
00118    struct mp3_private *p = s->_private;
00119    
00120    ExitMP3(&p->mp);
00121    return;
00122 }
00123 
00124 static int mp3_squeue(struct ast_filestream *s) 
00125 {
00126    struct mp3_private *p = s->_private;
00127    int res=0;
00128    
00129    p->lastseek = ftell(s->f);
00130    p->sbuflen = fread(p->sbuf, 1, MP3_SCACHE, s->f);
00131    if(p->sbuflen < 0) {
00132       ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", p->sbuflen, strerror(errno));
00133       return -1;
00134    }
00135    res = decodeMP3(&p->mp,p->sbuf,p->sbuflen,p->dbuf,MP3_DCACHE,&p->dbuflen);
00136    if(res != MP3_OK)
00137       return -1;
00138    p->sbuflen -= p->dbuflen;
00139    p->dbufoffset = 0;
00140    return 0;
00141 }
00142 
00143 static int mp3_dqueue(struct ast_filestream *s) 
00144 {
00145    struct mp3_private *p = s->_private;
00146    int res=0;
00147    
00148    if((res = decodeMP3(&p->mp,NULL,0,p->dbuf,MP3_DCACHE,&p->dbuflen)) == MP3_OK) {
00149       p->sbuflen -= p->dbuflen;
00150       p->dbufoffset = 0;
00151    }
00152    return res;
00153 }
00154 
00155 static int mp3_queue(struct ast_filestream *s)
00156 {
00157    struct mp3_private *p = s->_private;
00158    int res = 0, bytes = 0;
00159    
00160    if(p->seek) {
00161       ExitMP3(&p->mp);
00162       InitMP3(&p->mp, OUTSCALE);
00163       fseek(s->f, 0, SEEK_SET);
00164       p->sbuflen = p->dbuflen = p->offset = 0;
00165       while(p->offset < p->seek) {
00166          if(mp3_squeue(s))
00167             return -1;
00168          while(p->offset < p->seek && ((res = mp3_dqueue(s))) == MP3_OK) {
00169             for(bytes = 0 ; bytes < p->dbuflen ; bytes++) {
00170                p->dbufoffset++;
00171                p->offset++;
00172                if(p->offset >= p->seek)
00173                   break;
00174             }
00175          }
00176          if(res == MP3_ERR)
00177             return -1;
00178       }
00179       
00180       p->seek = 0;
00181       return 0;
00182    }
00183    if(p->dbuflen == 0) {
00184       if(p->sbuflen) {
00185          res = mp3_dqueue(s);
00186          if(res == MP3_ERR)
00187             return -1;
00188       }
00189       if(! p->sbuflen || res != MP3_OK) {
00190          if(mp3_squeue(s))
00191             return -1;
00192       }
00193       
00194    }
00195 
00196    return 0;
00197 }
00198 
00199 static struct ast_frame *mp3_read(struct ast_filestream *s, int *whennext)
00200 {
00201 
00202    struct mp3_private *p = s->_private;
00203    int delay =0;
00204    int save=0;
00205 
00206    /* Send a frame from the file to the appropriate channel */
00207 
00208    if(mp3_queue(s))
00209       return NULL;
00210 
00211    if(p->dbuflen) {
00212       for(p->buflen=0; p->buflen < MP3_BUFLEN && p->buflen < p->dbuflen; p->buflen++) {
00213          s->buf[p->buflen] = p->dbuf[p->buflen+p->dbufoffset];
00214          p->sbufoffset++;
00215       }
00216       p->dbufoffset += p->buflen;
00217       p->dbuflen -= p->buflen;
00218 
00219       if(p->buflen < MP3_BUFLEN) {
00220          if(mp3_queue(s))
00221             return NULL;
00222 
00223          for(save = p->buflen; p->buflen < MP3_BUFLEN; p->buflen++) {
00224             s->buf[p->buflen] = p->dbuf[(p->buflen-save)+p->dbufoffset];
00225             p->sbufoffset++;
00226          }
00227          p->dbufoffset += (MP3_BUFLEN - save);
00228          p->dbuflen -= (MP3_BUFLEN - save);
00229 
00230       } 
00231 
00232    }
00233    
00234    p->offset += p->buflen;
00235    delay = p->buflen/2;
00236    s->fr.frametype = AST_FRAME_VOICE;
00237    s->fr.subclass = AST_FORMAT_SLINEAR;
00238    s->fr.offset = AST_FRIENDLY_OFFSET;
00239    s->fr.datalen = p->buflen;
00240    s->fr.data = s->buf;
00241    s->fr.mallocd = 0;
00242    s->fr.samples = delay;
00243    *whennext = delay;
00244    return &s->fr;
00245 }
00246 
00247 
00248 static int mp3_write(struct ast_filestream *fs, struct ast_frame *f)
00249 {
00250    ast_log(LOG_ERROR,"I Can't write MP3 only read them.\n");
00251    return -1;
00252 
00253 }
00254 
00255 
00256 static int mp3_seek(struct ast_filestream *s, off_t sample_offset, int whence)
00257 {
00258    struct mp3_private *p = s->_private;
00259    off_t min,max,cur;
00260    long offset=0,samples;
00261    samples = sample_offset * 2;
00262 
00263    min = 0;
00264    fseek(s->f, 0, SEEK_END);
00265    max = ftell(s->f) * 100;
00266    cur = p->offset;
00267 
00268    if (whence == SEEK_SET)
00269       offset = samples + min;
00270    else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
00271       offset = samples + cur;
00272    else if (whence == SEEK_END)
00273       offset = max - samples;
00274    if (whence != SEEK_FORCECUR) {
00275       offset = (offset > max)?max:offset;
00276    }
00277 
00278    p->seek = offset;
00279    return p->seek;
00280    
00281 }
00282 
00283 static int mp3_rewrite(struct ast_filestream *s, const char *comment) 
00284 {
00285    ast_log(LOG_ERROR,"I Can't write MP3 only read them.\n");
00286    return -1;
00287 }
00288 
00289 static int mp3_trunc(struct ast_filestream *s) 
00290 {
00291 
00292    ast_log(LOG_ERROR,"I Can't write MP3 only read them.\n");
00293    return -1;
00294 }
00295 
00296 static off_t mp3_tell(struct ast_filestream *s)
00297 {
00298    struct mp3_private *p = s->_private;
00299    
00300    return p->offset/2;
00301 }
00302 
00303 static char *mp3_getcomment(struct ast_filestream *s)
00304 {
00305    return NULL;
00306 }
00307 
00308 static const struct ast_format mp3_f = {
00309    .name = "mp3",
00310    .exts = "mp3",
00311    .format = AST_FORMAT_SLINEAR,
00312    .open = mp3_open,
00313    .write = mp3_write,
00314    .rewrite = mp3_rewrite,
00315    .seek =  mp3_seek,
00316    .trunc = mp3_trunc,
00317    .tell =  mp3_tell,
00318    .read =  mp3_read,
00319    .close = mp3_close,
00320    .getcomment = mp3_getcomment,
00321    .buf_size = MP3_BUFLEN + AST_FRIENDLY_OFFSET,
00322    .desc_size = sizeof(struct mp3_private),
00323 };
00324 
00325 
00326 static int load_module(void)
00327 {
00328    InitMP3Constants();
00329    return ast_format_register(&mp3_f);
00330 }
00331 
00332 static int unload_module(void)
00333 {
00334    return ast_format_unregister(name);
00335 }  
00336 
00337 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "MP3 format [Any rate but 8000hz mono is optimal]");

Generated on Mon Mar 31 07:38:02 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1