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
00029
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
00034
00035 #include "asterisk/mod_format.h"
00036 #include "asterisk/module.h"
00037 #include "asterisk/endian.h"
00038 #include "asterisk/ulaw.h"
00039 #include "asterisk/alaw.h"
00040
00041 #define BUF_SIZE 160
00042
00043 static char ulaw_silence[BUF_SIZE];
00044 static char alaw_silence[BUF_SIZE];
00045
00046
00047
00048 #ifdef REALTIME_WRITE
00049 struct pcm_desc {
00050 unsigned long start_time;
00051 };
00052
00053
00054 static unsigned long get_time(void)
00055 {
00056 struct tms buf;
00057 clock_t cur;
00058
00059 cur = times( &buf );
00060 if( cur < 0 ) {
00061 ast_log( LOG_WARNING, "Cannot get current time\n" );
00062 return 0;
00063 }
00064 return cur * 1000 / sysconf( _SC_CLK_TCK );
00065 }
00066
00067 static int pcma_open(struct ast_filestream *s)
00068 {
00069 if (s->fmt->format == AST_FORMAT_ALAW)
00070 pd->starttime = get_time();
00071 return 0;
00072 }
00073
00074 static int pcma_rewrite(struct ast_filestream *s, const char *comment)
00075 {
00076 return pcma_open(s);
00077 }
00078 #endif
00079
00080 static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
00081 {
00082 int res;
00083
00084
00085
00086 s->fr.frametype = AST_FRAME_VOICE;
00087 s->fr.subclass.codec = s->fmt->format;
00088 s->fr.mallocd = 0;
00089 AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
00090 if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) {
00091 if (res)
00092 ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00093 return NULL;
00094 }
00095 s->fr.datalen = res;
00096 if (s->fmt->format == AST_FORMAT_G722)
00097 *whennext = s->fr.samples = res * 2;
00098 else
00099 *whennext = s->fr.samples = res;
00100 return &s->fr;
00101 }
00102
00103 static int pcm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
00104 {
00105 off_t cur, max, offset = 0;
00106 int ret = -1;
00107
00108 if ((cur = ftello(fs->f)) < 0) {
00109 ast_log(AST_LOG_WARNING, "Unable to determine current position in pcm filestream %p: %s\n", fs, strerror(errno));
00110 return -1;
00111 }
00112
00113 if (fseeko(fs->f, 0, SEEK_END) < 0) {
00114 ast_log(AST_LOG_WARNING, "Unable to seek to end of pcm filestream %p: %s\n", fs, strerror(errno));
00115 return -1;
00116 }
00117
00118 if ((max = ftello(fs->f)) < 0) {
00119 ast_log(AST_LOG_WARNING, "Unable to determine max position in pcm filestream %p: %s\n", fs, strerror(errno));
00120 return -1;
00121 }
00122
00123 switch (whence) {
00124 case SEEK_SET:
00125 offset = sample_offset;
00126 break;
00127 case SEEK_END:
00128 offset = max - sample_offset;
00129 break;
00130 case SEEK_CUR:
00131 case SEEK_FORCECUR:
00132 offset = cur + sample_offset;
00133 break;
00134 default:
00135 ast_log(LOG_WARNING, "invalid whence %d, assuming SEEK_SET\n", whence);
00136 offset = sample_offset;
00137 }
00138 if (offset < 0) {
00139 ast_log(LOG_WARNING, "negative offset %ld, resetting to 0\n", (long) offset);
00140 offset = 0;
00141 }
00142 if (whence == SEEK_FORCECUR && offset > max) {
00143 size_t left = offset - max;
00144 const char *src = (fs->fmt->format == AST_FORMAT_ALAW) ? alaw_silence : ulaw_silence;
00145
00146 while (left) {
00147 size_t written = fwrite(src, 1, (left > BUF_SIZE) ? BUF_SIZE : left, fs->f);
00148 if (written == -1)
00149 break;
00150 left -= written;
00151 }
00152 ret = 0;
00153 } else {
00154 if (offset > max) {
00155 ast_log(LOG_WARNING, "offset too large %ld, truncating to %ld\n", (long) offset, (long) max);
00156 offset = max;
00157 }
00158 ret = fseeko(fs->f, offset, SEEK_SET);
00159 }
00160 return ret;
00161 }
00162
00163 static int pcm_trunc(struct ast_filestream *fs)
00164 {
00165 int cur, fd;
00166
00167 if ((fd = fileno(fs->f)) < 0) {
00168 ast_log(AST_LOG_WARNING, "Unable to determine file descriptor for pcm filestream %p: %s\n", fs, strerror(errno));
00169 return -1;
00170 }
00171 if ((cur = ftello(fs->f)) < 0) {
00172 ast_log(AST_LOG_WARNING, "Unable to determine current position in pcm filestream %p: %s\n", fs, strerror(errno));
00173 return -1;
00174 }
00175
00176 return ftruncate(fd, cur);
00177 }
00178
00179 static off_t pcm_tell(struct ast_filestream *fs)
00180 {
00181 return ftello(fs->f);
00182 }
00183
00184 static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
00185 {
00186 int res;
00187
00188 if (f->frametype != AST_FRAME_VOICE) {
00189 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00190 return -1;
00191 }
00192 if (f->subclass.codec != fs->fmt->format) {
00193 ast_log(LOG_WARNING, "Asked to write incompatible format frame (%s)!\n", ast_getformatname(f->subclass.codec));
00194 return -1;
00195 }
00196
00197 #ifdef REALTIME_WRITE
00198 if (s->fmt->format == AST_FORMAT_ALAW) {
00199 struct pcm_desc *pd = (struct pcm_desc *)fs->_private;
00200 struct stat stat_buf;
00201 unsigned long cur_time = get_time();
00202 unsigned long fpos = ( cur_time - pd->start_time ) * 8;
00203
00204
00205
00206
00207 fstat(fileno(fs->f), &stat_buf );
00208 if (stat_buf.st_size > fpos )
00209 fpos += f->datalen;
00210
00211 if (stat_buf.st_size < fpos) {
00212
00213 char buf[1024];
00214 unsigned long cur, to_write;
00215
00216 cur = stat_buf.st_size;
00217 if (fseek(fs->f, cur, SEEK_SET) < 0) {
00218 ast_log( LOG_WARNING, "Cannot seek in file: %s\n", strerror(errno) );
00219 return -1;
00220 }
00221 memset(buf, 0x55, 512);
00222 while (cur < fpos) {
00223 to_write = fpos - cur;
00224 if (to_write > sizeof(buf))
00225 to_write = sizeof(buf);
00226 fwrite(buf, 1, to_write, fs->f);
00227 cur += to_write;
00228 }
00229 }
00230
00231 if (fseek(s->f, fpos, SEEK_SET) < 0) {
00232 ast_log( LOG_WARNING, "Cannot seek in file: %s\n", strerror(errno) );
00233 return -1;
00234 }
00235 }
00236 #endif
00237
00238 if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
00239 ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
00240 return -1;
00241 }
00242 return 0;
00243 }
00244
00245
00246
00247 #define AU_HEADER_SIZE 24
00248 #define AU_HEADER(var) uint32_t var[6]
00249
00250 #define AU_HDR_MAGIC_OFF 0
00251 #define AU_HDR_HDR_SIZE_OFF 1
00252 #define AU_HDR_DATA_SIZE_OFF 2
00253 #define AU_HDR_ENCODING_OFF 3
00254 #define AU_HDR_SAMPLE_RATE_OFF 4
00255 #define AU_HDR_CHANNELS_OFF 5
00256
00257 #define AU_ENC_8BIT_ULAW 1
00258
00259 #define AU_MAGIC 0x2e736e64
00260 #if __BYTE_ORDER == __BIG_ENDIAN
00261 #define htoll(b) (b)
00262 #define htols(b) (b)
00263 #define ltohl(b) (b)
00264 #define ltohs(b) (b)
00265 #else
00266 #if __BYTE_ORDER == __LITTLE_ENDIAN
00267 #define htoll(b) \
00268 (((((b) ) & 0xFF) << 24) | \
00269 ((((b) >> 8) & 0xFF) << 16) | \
00270 ((((b) >> 16) & 0xFF) << 8) | \
00271 ((((b) >> 24) & 0xFF) ))
00272 #define htols(b) \
00273 (((((b) ) & 0xFF) << 8) | \
00274 ((((b) >> 8) & 0xFF) ))
00275 #define ltohl(b) htoll(b)
00276 #define ltohs(b) htols(b)
00277 #else
00278 #error "Endianess not defined"
00279 #endif
00280 #endif
00281
00282 static int check_header(FILE *f)
00283 {
00284 AU_HEADER(header);
00285 uint32_t magic;
00286 uint32_t hdr_size;
00287 uint32_t data_size;
00288 uint32_t encoding;
00289 uint32_t sample_rate;
00290 uint32_t channels;
00291
00292 if (fread(header, 1, AU_HEADER_SIZE, f) != AU_HEADER_SIZE) {
00293 ast_log(LOG_WARNING, "Read failed (header)\n");
00294 return -1;
00295 }
00296 magic = ltohl(header[AU_HDR_MAGIC_OFF]);
00297 if (magic != (uint32_t) AU_MAGIC) {
00298 ast_log(LOG_WARNING, "Bad magic: 0x%x\n", magic);
00299 }
00300 hdr_size = ltohl(header[AU_HDR_HDR_SIZE_OFF]);
00301 if (hdr_size < AU_HEADER_SIZE) {
00302 hdr_size = AU_HEADER_SIZE;
00303 }
00304
00305 encoding = ltohl(header[AU_HDR_ENCODING_OFF]);
00306 if (encoding != AU_ENC_8BIT_ULAW) {
00307 ast_log(LOG_WARNING, "Unexpected format: %u. Only 8bit ULAW allowed (%d)\n", encoding, AU_ENC_8BIT_ULAW);
00308 return -1;
00309 }
00310 sample_rate = ltohl(header[AU_HDR_SAMPLE_RATE_OFF]);
00311 if (sample_rate != DEFAULT_SAMPLE_RATE) {
00312 ast_log(LOG_WARNING, "Sample rate can only be 8000 not %u\n", sample_rate);
00313 return -1;
00314 }
00315 channels = ltohl(header[AU_HDR_CHANNELS_OFF]);
00316 if (channels != 1) {
00317 ast_log(LOG_WARNING, "Not in mono: channels=%u\n", channels);
00318 return -1;
00319 }
00320
00321 fseek(f, 0, SEEK_END);
00322 data_size = ftell(f) - hdr_size;
00323 if (fseek(f, hdr_size, SEEK_SET) == -1 ) {
00324 ast_log(LOG_WARNING, "Failed to skip to data: %u\n", hdr_size);
00325 return -1;
00326 }
00327 return data_size;
00328 }
00329
00330 static int update_header(FILE *f)
00331 {
00332 off_t cur, end;
00333 uint32_t datalen;
00334 int bytes;
00335
00336 cur = ftell(f);
00337 fseek(f, 0, SEEK_END);
00338 end = ftell(f);
00339
00340 bytes = end - AU_HEADER_SIZE;
00341 datalen = htoll(bytes);
00342
00343 if (cur < 0) {
00344 ast_log(LOG_WARNING, "Unable to find our position\n");
00345 return -1;
00346 }
00347 if (fseek(f, AU_HDR_DATA_SIZE_OFF * sizeof(uint32_t), SEEK_SET)) {
00348 ast_log(LOG_WARNING, "Unable to set our position\n");
00349 return -1;
00350 }
00351 if (fwrite(&datalen, 1, sizeof(datalen), f) != sizeof(datalen)) {
00352 ast_log(LOG_WARNING, "Unable to set write file size\n");
00353 return -1;
00354 }
00355 if (fseek(f, cur, SEEK_SET)) {
00356 ast_log(LOG_WARNING, "Unable to return to position\n");
00357 return -1;
00358 }
00359 return 0;
00360 }
00361
00362 static int write_header(FILE *f)
00363 {
00364 AU_HEADER(header);
00365
00366 header[AU_HDR_MAGIC_OFF] = htoll((uint32_t) AU_MAGIC);
00367 header[AU_HDR_HDR_SIZE_OFF] = htoll(AU_HEADER_SIZE);
00368 header[AU_HDR_DATA_SIZE_OFF] = 0;
00369 header[AU_HDR_ENCODING_OFF] = htoll(AU_ENC_8BIT_ULAW);
00370 header[AU_HDR_SAMPLE_RATE_OFF] = htoll(DEFAULT_SAMPLE_RATE);
00371 header[AU_HDR_CHANNELS_OFF] = htoll(1);
00372
00373
00374 fseek(f, 0, SEEK_SET);
00375 if (fwrite(header, 1, AU_HEADER_SIZE, f) != AU_HEADER_SIZE) {
00376 ast_log(LOG_WARNING, "Unable to write header\n");
00377 return -1;
00378 }
00379 return 0;
00380 }
00381
00382 static int au_open(struct ast_filestream *s)
00383 {
00384 if (check_header(s->f) < 0)
00385 return -1;
00386 return 0;
00387 }
00388
00389 static int au_rewrite(struct ast_filestream *s, const char *comment)
00390 {
00391 if (write_header(s->f))
00392 return -1;
00393 return 0;
00394 }
00395
00396
00397 static int au_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
00398 {
00399 off_t min = AU_HEADER_SIZE, max, cur;
00400 long offset = 0, bytes;
00401
00402 if (fs->fmt->format == AST_FORMAT_G722)
00403 bytes = sample_offset / 2;
00404 else
00405 bytes = sample_offset;
00406
00407 if ((cur = ftello(fs->f)) < 0) {
00408 ast_log(AST_LOG_WARNING, "Unable to determine current position in au filestream %p: %s\n", fs, strerror(errno));
00409 return -1;
00410 }
00411
00412 if (fseeko(fs->f, 0, SEEK_END) < 0) {
00413 ast_log(AST_LOG_WARNING, "Unable to seek to end of au filestream %p: %s\n", fs, strerror(errno));
00414 return -1;
00415 }
00416
00417 if ((max = ftello(fs->f)) < 0) {
00418 ast_log(AST_LOG_WARNING, "Unable to determine max position in au filestream %p: %s\n", fs, strerror(errno));
00419 return -1;
00420 }
00421
00422 if (whence == SEEK_SET)
00423 offset = bytes + min;
00424 else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
00425 offset = bytes + cur;
00426 else if (whence == SEEK_END)
00427 offset = max - bytes;
00428
00429 if (whence != SEEK_FORCECUR) {
00430 offset = (offset > max) ? max : offset;
00431 }
00432
00433
00434 offset = (offset < min) ? min : offset;
00435
00436 return fseeko(fs->f, offset, SEEK_SET);
00437 }
00438
00439 static int au_trunc(struct ast_filestream *fs)
00440 {
00441 int fd;
00442 off_t cur;
00443
00444 if ((fd = fileno(fs->f)) < 0) {
00445 ast_log(AST_LOG_WARNING, "Unable to determine file descriptor for au filestream %p: %s\n", fs, strerror(errno));
00446 return -1;
00447 }
00448 if ((cur = ftello(fs->f)) < 0) {
00449 ast_log(AST_LOG_WARNING, "Unable to determine current position in au filestream %p: %s\n", fs, strerror(errno));
00450 return -1;
00451 }
00452
00453 if (ftruncate(fd, cur)) {
00454 return -1;
00455 }
00456 return update_header(fs->f);
00457 }
00458
00459 static off_t au_tell(struct ast_filestream *fs)
00460 {
00461 off_t offset = ftello(fs->f);
00462 return offset - AU_HEADER_SIZE;
00463 }
00464
00465 static const struct ast_format alaw_f = {
00466 .name = "alaw",
00467 .exts = "alaw|al|alw",
00468 .format = AST_FORMAT_ALAW,
00469 .write = pcm_write,
00470 .seek = pcm_seek,
00471 .trunc = pcm_trunc,
00472 .tell = pcm_tell,
00473 .read = pcm_read,
00474 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00475 #ifdef REALTIME_WRITE
00476 .open = pcma_open,
00477 .rewrite = pcma_rewrite,
00478 .desc_size = sizeof(struct pcm_desc),
00479 #endif
00480 };
00481
00482 static const struct ast_format pcm_f = {
00483 .name = "pcm",
00484 .exts = "pcm|ulaw|ul|mu|ulw",
00485 .format = AST_FORMAT_ULAW,
00486 .write = pcm_write,
00487 .seek = pcm_seek,
00488 .trunc = pcm_trunc,
00489 .tell = pcm_tell,
00490 .read = pcm_read,
00491 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00492 };
00493
00494 static const struct ast_format g722_f = {
00495 .name = "g722",
00496 .exts = "g722",
00497 .format = AST_FORMAT_G722,
00498 .write = pcm_write,
00499 .seek = pcm_seek,
00500 .trunc = pcm_trunc,
00501 .tell = pcm_tell,
00502 .read = pcm_read,
00503 .buf_size = (BUF_SIZE * 2) + AST_FRIENDLY_OFFSET,
00504 };
00505
00506 static const struct ast_format au_f = {
00507 .name = "au",
00508 .exts = "au",
00509 .format = AST_FORMAT_ULAW,
00510 .open = au_open,
00511 .rewrite = au_rewrite,
00512 .write = pcm_write,
00513 .seek = au_seek,
00514 .trunc = au_trunc,
00515 .tell = au_tell,
00516 .read = pcm_read,
00517 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00518 };
00519
00520 static int load_module(void)
00521 {
00522 int i;
00523
00524
00525 for (i = 0; i < ARRAY_LEN(ulaw_silence); i++)
00526 ulaw_silence[i] = AST_LIN2MU(0);
00527 for (i = 0; i < ARRAY_LEN(alaw_silence); i++)
00528 alaw_silence[i] = AST_LIN2A(0);
00529
00530 if ( ast_format_register(&pcm_f)
00531 || ast_format_register(&alaw_f)
00532 || ast_format_register(&au_f)
00533 || ast_format_register(&g722_f) )
00534 return AST_MODULE_LOAD_FAILURE;
00535 return AST_MODULE_LOAD_SUCCESS;
00536 }
00537
00538 static int unload_module(void)
00539 {
00540 return ast_format_unregister(pcm_f.name)
00541 || ast_format_unregister(alaw_f.name)
00542 || ast_format_unregister(au_f.name)
00543 || ast_format_unregister(g722_f.name);
00544 }
00545
00546 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw/Sun uLaw/ALaw 8KHz (PCM,PCMA,AU), G.722 16Khz",
00547 .load = load_module,
00548 .unload = unload_module,
00549 .load_pri = AST_MODPRI_APP_DEPEND
00550 );