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