00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00064 FILE *f;
00065 struct ast_channel *owner;
00066 struct ast_frame fr;
00067 char waste[AST_FRIENDLY_OFFSET];
00068 char empty;
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
00124
00125 hdr_size = AU_HEADER_SIZE;
00126
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
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
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
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
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
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
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 }