Sun Aug 6 15:02:40 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

format_au.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2005, Andriy Pylypenko
00005  * Code based on format_wav.c by Mark Spencer
00006  *
00007  * See http://www.asterisk.org for more information about
00008  * the Asterisk project. Please do not directly contact
00009  * any of the maintainers of this project for assistance;
00010  * the project provides a web site, mailing lists and IRC
00011  * channels for your use.
00012  *
00013  * This program is free software, distributed under the terms of
00014  * the GNU General Public License Version 2. See the LICENSE file
00015  * at the top of the source tree.
00016  */
00017 
00018 /*! 
00019  * \file
00020  *
00021  * \brief Work with Sun Microsystems AU format.
00022  *
00023  * signed linear
00024  * \arg File extension: au
00025  * \ingroup formats
00026  */
00027  
00028 #include <stdlib.h>
00029 #include <sys/time.h>
00030 #include <stdio.h>
00031 #include <unistd.h>
00032 #include <errno.h>
00033 #include <string.h>
00034 
00035 #include "asterisk.h"
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00038 
00039 #include "asterisk/lock.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/logger.h"
00043 #include "asterisk/sched.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/endian.h"
00046 
00047 #define BUF_SIZE     160
00048 
00049 #define AU_HEADER_SIZE     24
00050 #define AU_HEADER(var)     u_int32_t var[6]
00051 
00052 #define AU_HDR_MAGIC_OFF   0
00053 #define AU_HDR_HDR_SIZE_OFF   1
00054 #define AU_HDR_DATA_SIZE_OFF  2
00055 #define AU_HDR_ENCODING_OFF   3
00056 #define AU_HDR_SAMPLE_RATE_OFF   4
00057 #define AU_HDR_CHANNELS_OFF   5
00058 
00059 #define AU_ENC_8BIT_ULAW   1
00060 
00061 struct ast_filestream {
00062    void *reserved[AST_RESERVED_POINTERS];
00063    /* This is what a filestream means to us */
00064    FILE *f;             /* Descriptor */
00065    struct ast_channel *owner;
00066    struct ast_frame fr;       /* Frame information */
00067    char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
00068    char empty;          /* Empty character */
00069    short buf[BUF_SIZE];
00070 };
00071 
00072 
00073 AST_MUTEX_DEFINE_STATIC(au_lock);
00074 static int localusecnt = 0;
00075 
00076 static char *name = "au";
00077 static char *desc = "Sun Microsystems AU format (signed linear)";
00078 static char *exts = "au";
00079 
00080 
00081 #define AU_MAGIC 0x2e736e64
00082 #if __BYTE_ORDER == __BIG_ENDIAN
00083 #define htoll(b) (b)
00084 #define htols(b) (b)
00085 #define ltohl(b) (b)
00086 #define ltohs(b) (b)
00087 #else
00088 #if __BYTE_ORDER == __LITTLE_ENDIAN
00089 #define htoll(b)  \
00090           (((((b)      ) & 0xFF) << 24) | \
00091           ((((b) >>  8) & 0xFF) << 16) | \
00092          ((((b) >> 16) & 0xFF) <<  8) | \
00093          ((((b) >> 24) & 0xFF)      ))
00094 #define htols(b) \
00095           (((((b)      ) & 0xFF) << 8) | \
00096          ((((b) >> 8) & 0xFF)      ))
00097 #define ltohl(b) htoll(b)
00098 #define ltohs(b) htols(b)
00099 #else
00100 #error "Endianess not defined"
00101 #endif
00102 #endif
00103 
00104 
00105 static int check_header(FILE *f)
00106 {
00107    AU_HEADER(header);
00108    u_int32_t magic;
00109    u_int32_t hdr_size;
00110    u_int32_t data_size;
00111    u_int32_t encoding;
00112    u_int32_t sample_rate;
00113    u_int32_t channels;
00114 
00115    if (fread(header, 1, AU_HEADER_SIZE, f) != AU_HEADER_SIZE) {
00116       ast_log(LOG_WARNING, "Read failed (header)\n");
00117       return -1;
00118    }
00119    magic = ltohl(header[AU_HDR_MAGIC_OFF]);
00120    if (magic != (u_int32_t) AU_MAGIC) {
00121       ast_log(LOG_WARNING, "Bad magic: 0x%x\n", magic);
00122    }
00123 /* hdr_size = ltohl(header[AU_HDR_HDR_SIZE_OFF]);
00124    if (hdr_size < AU_HEADER_SIZE)*/
00125    hdr_size = AU_HEADER_SIZE;
00126 /* data_size = ltohl(header[AU_HDR_DATA_SIZE_OFF]); */
00127    encoding = ltohl(header[AU_HDR_ENCODING_OFF]);
00128    if (encoding != AU_ENC_8BIT_ULAW) {
00129       ast_log(LOG_WARNING, "Unexpected format: %d. Only 8bit ULAW allowed (%d)\n", encoding, AU_ENC_8BIT_ULAW);
00130       return -1;
00131    }
00132    sample_rate = ltohl(header[AU_HDR_SAMPLE_RATE_OFF]);
00133    if (sample_rate != 8000) {
00134       ast_log(LOG_WARNING, "Sample rate can only be 8000 not %d\n", sample_rate);
00135       return -1;
00136    }
00137    channels = ltohl(header[AU_HDR_CHANNELS_OFF]);
00138    if (channels != 1) {
00139       ast_log(LOG_WARNING, "Not in mono: channels=%d\n", channels);
00140       return -1;
00141    }
00142    /* Skip to data */
00143    fseek(f, 0, SEEK_END);
00144    data_size = ftell(f) - hdr_size;
00145    if (fseek(f, hdr_size, SEEK_SET) == -1 ) {
00146       ast_log(LOG_WARNING, "Failed to skip to data: %d\n", hdr_size);
00147       return -1;
00148    }
00149    return data_size;
00150 }
00151 
00152 static int update_header(FILE *f)
00153 {
00154    off_t cur, end;
00155    u_int32_t datalen;
00156    int bytes;
00157 
00158    cur = ftell(f);
00159    fseek(f, 0, SEEK_END);
00160    end = ftell(f);
00161    /* data starts 24 bytes in */
00162    bytes = end - AU_HEADER_SIZE;
00163    datalen = htoll(bytes);
00164 
00165    if (cur < 0) {
00166       ast_log(LOG_WARNING, "Unable to find our position\n");
00167       return -1;
00168    }
00169    if (fseek(f, AU_HDR_DATA_SIZE_OFF * sizeof(u_int32_t), SEEK_SET)) {
00170       ast_log(LOG_WARNING, "Unable to set our position\n");
00171       return -1;
00172    }
00173    if (fwrite(&datalen, 1, sizeof(datalen), f) != sizeof(datalen)) {
00174       ast_log(LOG_WARNING, "Unable to set write file size\n");
00175       return -1;
00176    }
00177    if (fseek(f, cur, SEEK_SET)) {
00178       ast_log(LOG_WARNING, "Unable to return to position\n");
00179       return -1;
00180    }
00181    return 0;
00182 }
00183 
00184 static int write_header(FILE *f)
00185 {
00186    AU_HEADER(header);
00187 
00188    header[AU_HDR_MAGIC_OFF] = htoll((u_int32_t) AU_MAGIC);
00189    header[AU_HDR_HDR_SIZE_OFF] = htoll(AU_HEADER_SIZE);
00190    header[AU_HDR_DATA_SIZE_OFF] = 0;
00191    header[AU_HDR_ENCODING_OFF] = htoll(AU_ENC_8BIT_ULAW);
00192    header[AU_HDR_SAMPLE_RATE_OFF] = htoll(8000);
00193    header[AU_HDR_CHANNELS_OFF] = htoll(1);
00194 
00195    /* Write an au header, ignoring sizes which will be filled in later */
00196    fseek(f, 0, SEEK_SET);
00197    if (fwrite(header, 1, AU_HEADER_SIZE, f) != AU_HEADER_SIZE) {
00198       ast_log(LOG_WARNING, "Unable to write header\n");
00199       return -1;
00200    }
00201    return 0;
00202 }
00203 
00204 static struct ast_filestream *au_open(FILE *f)
00205 {
00206    struct ast_filestream *tmp;
00207 
00208    if (!(tmp = malloc(sizeof(struct ast_filestream)))) {
00209       ast_log(LOG_ERROR, "Out of memory\n");
00210       return NULL;
00211    }
00212 
00213    memset(tmp, 0, sizeof(struct ast_filestream));
00214    if (check_header(f) < 0) {
00215       free(tmp);
00216       return NULL;
00217    }
00218    if (ast_mutex_lock(&au_lock)) {
00219       ast_log(LOG_WARNING, "Unable to lock au count\n");
00220       free(tmp);
00221       return NULL;
00222    }
00223    tmp->f = f;
00224    tmp->fr.data = tmp->buf;
00225    tmp->fr.frametype = AST_FRAME_VOICE;
00226    tmp->fr.subclass = AST_FORMAT_ULAW;
00227    /* datalen will vary for each frame */
00228    tmp->fr.src = name;
00229    tmp->fr.mallocd = 0;
00230    localusecnt++;
00231    ast_mutex_unlock(&au_lock);
00232    ast_update_use_count();
00233    return tmp;
00234 }
00235 
00236 static struct ast_filestream *au_rewrite(FILE *f, const char *comment)
00237 {
00238    struct ast_filestream *tmp;
00239 
00240    if ((tmp = malloc(sizeof(struct ast_filestream))) == NULL) {
00241       ast_log(LOG_ERROR, "Out of memory\n");
00242       return NULL;
00243    }
00244 
00245    memset(tmp, 0, sizeof(struct ast_filestream));
00246    if (write_header(f)) {
00247       free(tmp);
00248       return NULL;
00249    }
00250    if (ast_mutex_lock(&au_lock)) {
00251       ast_log(LOG_WARNING, "Unable to lock au count\n");
00252       free(tmp);
00253       return NULL;
00254    }
00255    tmp->f = f;
00256    localusecnt++;
00257    ast_mutex_unlock(&au_lock);
00258    ast_update_use_count();
00259    return tmp;
00260 }
00261 
00262 static void au_close(struct ast_filestream *s)
00263 {
00264    if (ast_mutex_lock(&au_lock)) {
00265       ast_log(LOG_WARNING, "Unable to lock au count\n");
00266       return;
00267    }
00268    localusecnt--;
00269    ast_mutex_unlock(&au_lock);
00270    ast_update_use_count();
00271    fclose(s->f);
00272    free(s);
00273 }
00274 
00275 static struct ast_frame *au_read(struct ast_filestream *s, int *whennext)
00276 {
00277    int res;
00278    int delay;
00279    /* Send a frame from the file to the appropriate channel */
00280 
00281    s->fr.frametype = AST_FRAME_VOICE;
00282    s->fr.subclass = AST_FORMAT_ULAW;
00283    s->fr.offset = AST_FRIENDLY_OFFSET;
00284    s->fr.mallocd = 0;
00285    s->fr.data = s->buf;
00286    if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) {
00287       if (res)
00288          ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00289       return NULL;
00290    }
00291    s->fr.samples = res;
00292    s->fr.datalen = res;
00293    delay = s->fr.samples;
00294    *whennext = delay;
00295    return &s->fr;
00296 }
00297 
00298 static int au_write(struct ast_filestream *fs, struct ast_frame *f)
00299 {
00300    int res;
00301 
00302    if (f->frametype != AST_FRAME_VOICE) {
00303       ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00304       return -1;
00305    }
00306    if (f->subclass != AST_FORMAT_ULAW) {
00307       ast_log(LOG_WARNING, "Asked to write non-ulaw frame (%d)!\n", f->subclass);
00308       return -1;
00309    }
00310    if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
00311          ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
00312          return -1;
00313    }
00314    update_header(fs->f);
00315    return 0;
00316 }
00317 
00318 static int au_seek(struct ast_filestream *fs, long sample_offset, int whence)
00319 {
00320    off_t min, max, cur;
00321    long offset = 0, samples;
00322    
00323    samples = sample_offset;
00324    min = AU_HEADER_SIZE;
00325    cur = ftell(fs->f);
00326    fseek(fs->f, 0, SEEK_END);
00327    max = ftell(fs->f);
00328    if (whence == SEEK_SET)
00329       offset = samples + min;
00330    else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
00331       offset = samples + cur;
00332    else if (whence == SEEK_END)
00333       offset = max - samples;
00334         if (whence != SEEK_FORCECUR) {
00335       offset = (offset > max) ? max : offset;
00336    }
00337    /* always protect the header space. */
00338    offset = (offset < min) ? min : offset;
00339    return fseek(fs->f, offset, SEEK_SET);
00340 }
00341 
00342 static int au_trunc(struct ast_filestream *fs)
00343 {
00344    if (ftruncate(fileno(fs->f), ftell(fs->f)))
00345       return -1;
00346    return update_header(fs->f);
00347 }
00348 
00349 static long au_tell(struct ast_filestream *fs)
00350 {
00351    off_t offset;
00352 
00353    offset = ftell(fs->f);
00354    return offset - AU_HEADER_SIZE;
00355 }
00356 
00357 static char *au_getcomment(struct ast_filestream *s)
00358 {
00359    return NULL;
00360 }
00361 
00362 int load_module()
00363 {
00364    return ast_format_register(name, exts, AST_FORMAT_ULAW,
00365                au_open,
00366                au_rewrite,
00367                au_write,
00368                au_seek,
00369                au_trunc,
00370                au_tell,
00371                au_read,
00372                au_close,
00373                au_getcomment);
00374 }
00375 
00376 int unload_module()
00377 {
00378    return ast_format_unregister(name);
00379 }
00380 
00381 int usecount()
00382 {
00383    return localusecnt;
00384 }
00385 
00386 char *description()
00387 {
00388    return desc;
00389 }
00390 
00391 char *key()
00392 {
00393    return ASTERISK_GPL_KEY;
00394 }

Generated on Sun Aug 6 15:02:40 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2