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
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00037
00038 #include <vorbis/codec.h>
00039 #include <vorbis/vorbisenc.h>
00040
00041 #ifdef _WIN32
00042 #include <io.h>
00043 #endif
00044
00045 #include "asterisk/mod_format.h"
00046 #include "asterisk/module.h"
00047
00048
00049
00050
00051
00052 #define SAMPLES_MAX 160
00053 #define BUF_SIZE (2*SAMPLES_MAX)
00054
00055 #define BLOCK_SIZE 4096
00056
00057 struct vorbis_desc {
00058
00059 ogg_sync_state oy;
00060 ogg_stream_state os;
00061 ogg_page og;
00062 ogg_packet op;
00063
00064
00065 vorbis_info vi;
00066 vorbis_comment vc;
00067 vorbis_dsp_state vd;
00068 vorbis_block vb;
00069
00070
00071 int writing;
00072
00073
00074 int eos;
00075 };
00076
00077
00078
00079
00080
00081
00082 static int ogg_vorbis_open(struct ast_filestream *s)
00083 {
00084 int i;
00085 int bytes;
00086 int result;
00087 char **ptr;
00088 char *buffer;
00089 struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private;
00090
00091 tmp->writing = 0;
00092
00093 ogg_sync_init(&tmp->oy);
00094
00095 buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
00096 bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
00097 ogg_sync_wrote(&tmp->oy, bytes);
00098
00099 result = ogg_sync_pageout(&tmp->oy, &tmp->og);
00100 if (result != 1) {
00101 if(bytes < BLOCK_SIZE) {
00102 ast_log(LOG_ERROR, "Run out of data...\n");
00103 } else {
00104 ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
00105 }
00106 ogg_sync_clear(&tmp->oy);
00107 return -1;
00108 }
00109
00110 ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
00111 vorbis_info_init(&tmp->vi);
00112 vorbis_comment_init(&tmp->vc);
00113
00114 if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) {
00115 ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
00116 error:
00117 ogg_stream_clear(&tmp->os);
00118 vorbis_comment_clear(&tmp->vc);
00119 vorbis_info_clear(&tmp->vi);
00120 ogg_sync_clear(&tmp->oy);
00121 return -1;
00122 }
00123
00124 if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) {
00125 ast_log(LOG_ERROR, "Error reading initial header packet.\n");
00126 goto error;
00127 }
00128
00129 if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) {
00130 ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
00131 goto error;
00132 }
00133
00134 for (i = 0; i < 2 ; ) {
00135 while (i < 2) {
00136 result = ogg_sync_pageout(&tmp->oy, &tmp->og);
00137 if (result == 0)
00138 break;
00139 if (result == 1) {
00140 ogg_stream_pagein(&tmp->os, &tmp->og);
00141 while(i < 2) {
00142 result = ogg_stream_packetout(&tmp->os,&tmp->op);
00143 if(result == 0)
00144 break;
00145 if(result < 0) {
00146 ast_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n");
00147 goto error;
00148 }
00149 vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
00150 i++;
00151 }
00152 }
00153 }
00154
00155 buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
00156 bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
00157 if (bytes == 0 && i < 2) {
00158 ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
00159 goto error;
00160 }
00161 ogg_sync_wrote(&tmp->oy, bytes);
00162 }
00163
00164 for (ptr = tmp->vc.user_comments; *ptr; ptr++)
00165 ast_debug(1, "OGG/Vorbis comment: %s\n", *ptr);
00166 ast_debug(1, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate);
00167 ast_debug(1, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor);
00168
00169 if (tmp->vi.channels != 1) {
00170 ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
00171 goto error;
00172 }
00173
00174 if (tmp->vi.rate != DEFAULT_SAMPLE_RATE) {
00175 ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
00176 vorbis_block_clear(&tmp->vb);
00177 vorbis_dsp_clear(&tmp->vd);
00178 goto error;
00179 }
00180
00181 vorbis_synthesis_init(&tmp->vd, &tmp->vi);
00182 vorbis_block_init(&tmp->vd, &tmp->vb);
00183
00184 return 0;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193 static int ogg_vorbis_rewrite(struct ast_filestream *s,
00194 const char *comment)
00195 {
00196 ogg_packet header;
00197 ogg_packet header_comm;
00198 ogg_packet header_code;
00199 struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private;
00200
00201 tmp->writing = 1;
00202
00203 vorbis_info_init(&tmp->vi);
00204
00205 if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) {
00206 ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n");
00207 return -1;
00208 }
00209
00210 vorbis_comment_init(&tmp->vc);
00211 vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX");
00212 if (comment)
00213 vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment);
00214
00215 vorbis_analysis_init(&tmp->vd, &tmp->vi);
00216 vorbis_block_init(&tmp->vd, &tmp->vb);
00217
00218 ogg_stream_init(&tmp->os, ast_random());
00219
00220 vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm,
00221 &header_code);
00222 ogg_stream_packetin(&tmp->os, &header);
00223 ogg_stream_packetin(&tmp->os, &header_comm);
00224 ogg_stream_packetin(&tmp->os, &header_code);
00225
00226 while (!tmp->eos) {
00227 if (ogg_stream_flush(&tmp->os, &tmp->og) == 0)
00228 break;
00229 if (!fwrite(tmp->og.header, 1, tmp->og.header_len, s->f)) {
00230 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00231 }
00232 if (!fwrite(tmp->og.body, 1, tmp->og.body_len, s->f)) {
00233 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00234 }
00235 if (ogg_page_eos(&tmp->og))
00236 tmp->eos = 1;
00237 }
00238
00239 return 0;
00240 }
00241
00242
00243
00244
00245
00246
00247 static void write_stream(struct vorbis_desc *s, FILE *f)
00248 {
00249 while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
00250 vorbis_analysis(&s->vb, NULL);
00251 vorbis_bitrate_addblock(&s->vb);
00252
00253 while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) {
00254 ogg_stream_packetin(&s->os, &s->op);
00255 while (!s->eos) {
00256 if (ogg_stream_pageout(&s->os, &s->og) == 0) {
00257 break;
00258 }
00259 if (!fwrite(s->og.header, 1, s->og.header_len, f)) {
00260 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00261 }
00262 if (!fwrite(s->og.body, 1, s->og.body_len, f)) {
00263 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00264 }
00265 if (ogg_page_eos(&s->og)) {
00266 s->eos = 1;
00267 }
00268 }
00269 }
00270 }
00271 }
00272
00273
00274
00275
00276
00277
00278
00279 static int ogg_vorbis_write(struct ast_filestream *fs, struct ast_frame *f)
00280 {
00281 int i;
00282 float **buffer;
00283 short *data;
00284 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
00285
00286 if (!s->writing) {
00287 ast_log(LOG_ERROR, "This stream is not set up for writing!\n");
00288 return -1;
00289 }
00290
00291 if (f->frametype != AST_FRAME_VOICE) {
00292 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00293 return -1;
00294 }
00295 if (f->subclass.codec != AST_FORMAT_SLINEAR) {
00296 ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%s)!\n",
00297 ast_getformatname(f->subclass.codec));
00298 return -1;
00299 }
00300 if (!f->datalen)
00301 return -1;
00302
00303 data = (short *) f->data.ptr;
00304
00305 buffer = vorbis_analysis_buffer(&s->vd, f->samples);
00306
00307 for (i = 0; i < f->samples; i++)
00308 buffer[0][i] = (double)data[i] / 32768.0;
00309
00310 vorbis_analysis_wrote(&s->vd, f->samples);
00311
00312 write_stream(s, fs->f);
00313
00314 return 0;
00315 }
00316
00317
00318
00319
00320
00321 static void ogg_vorbis_close(struct ast_filestream *fs)
00322 {
00323 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
00324
00325 if (s->writing) {
00326
00327
00328 vorbis_analysis_wrote(&s->vd, 0);
00329 write_stream(s, fs->f);
00330 }
00331
00332 ogg_stream_clear(&s->os);
00333 vorbis_block_clear(&s->vb);
00334 vorbis_dsp_clear(&s->vd);
00335 vorbis_comment_clear(&s->vc);
00336 vorbis_info_clear(&s->vi);
00337
00338 if (s->writing) {
00339 ogg_sync_clear(&s->oy);
00340 }
00341 }
00342
00343
00344
00345
00346
00347
00348
00349 static int read_samples(struct ast_filestream *fs, float ***pcm)
00350 {
00351 int samples_in;
00352 int result;
00353 char *buffer;
00354 int bytes;
00355 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
00356
00357 while (1) {
00358 samples_in = vorbis_synthesis_pcmout(&s->vd, pcm);
00359 if (samples_in > 0) {
00360 return samples_in;
00361 }
00362
00363
00364
00365 result = ogg_stream_packetout(&s->os, &s->op);
00366 if (result > 0) {
00367
00368 if (vorbis_synthesis(&s->vb, &s->op) == 0) {
00369 vorbis_synthesis_blockin(&s->vd, &s->vb);
00370 }
00371
00372 continue;
00373 }
00374
00375 if (result < 0)
00376 ast_log(LOG_WARNING,
00377 "Corrupt or missing data at this page position; continuing...\n");
00378
00379
00380
00381 if (s->eos) {
00382
00383 return -1;
00384 }
00385
00386 while (!s->eos) {
00387
00388 result = ogg_sync_pageout(&s->oy, &s->og);
00389 if (result > 0) {
00390
00391
00392 result = ogg_stream_pagein(&s->os, &s->og);
00393 if (result == 0) {
00394
00395 if (ogg_page_eos(&s->og)) {
00396 s->eos = 1;
00397 }
00398 break;
00399 }
00400 ast_log(LOG_WARNING,
00401 "Invalid page in the bitstream; continuing...\n");
00402 }
00403
00404 if (result < 0)
00405 ast_log(LOG_WARNING,
00406 "Corrupt or missing data in bitstream; continuing...\n");
00407
00408
00409
00410 buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
00411
00412 bytes = fread(buffer, 1, BLOCK_SIZE, fs->f);
00413
00414 ogg_sync_wrote(&s->oy, bytes);
00415 if (bytes == 0) {
00416 s->eos = 1;
00417 }
00418 }
00419 }
00420 }
00421
00422
00423
00424
00425
00426
00427
00428 static struct ast_frame *ogg_vorbis_read(struct ast_filestream *fs,
00429 int *whennext)
00430 {
00431 int clipflag = 0;
00432 int i;
00433 int j;
00434 double accumulator[SAMPLES_MAX];
00435 int val;
00436 int samples_in;
00437 int samples_out = 0;
00438 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
00439 short *buf;
00440
00441 fs->fr.frametype = AST_FRAME_VOICE;
00442 fs->fr.subclass.codec = AST_FORMAT_SLINEAR;
00443 fs->fr.mallocd = 0;
00444 AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
00445 buf = (short *)(fs->fr.data.ptr);
00446
00447 while (samples_out != SAMPLES_MAX) {
00448 float **pcm;
00449 int len = SAMPLES_MAX - samples_out;
00450
00451
00452 samples_in = read_samples(fs, &pcm);
00453 if (samples_in <= 0)
00454 break;
00455
00456
00457
00458
00459 clipflag = 0;
00460 if (samples_in > len)
00461 samples_in = len;
00462 for (j = 0; j < samples_in; j++)
00463 accumulator[j] = 0.0;
00464
00465 for (i = 0; i < s->vi.channels; i++) {
00466 float *mono = pcm[i];
00467 for (j = 0; j < samples_in; j++)
00468 accumulator[j] += mono[j];
00469 }
00470
00471 for (j = 0; j < samples_in; j++) {
00472 val = accumulator[j] * 32767.0 / s->vi.channels;
00473 if (val > 32767) {
00474 val = 32767;
00475 clipflag = 1;
00476 } else if (val < -32768) {
00477 val = -32768;
00478 clipflag = 1;
00479 }
00480 buf[samples_out + j] = val;
00481 }
00482
00483 if (clipflag)
00484 ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long) (s->vd.sequence));
00485
00486 vorbis_synthesis_read(&s->vd, samples_in);
00487 samples_out += samples_in;
00488 }
00489
00490 if (samples_out > 0) {
00491 fs->fr.datalen = samples_out * 2;
00492 fs->fr.samples = samples_out;
00493 *whennext = samples_out;
00494
00495 return &fs->fr;
00496 } else {
00497 return NULL;
00498 }
00499 }
00500
00501
00502
00503
00504
00505
00506
00507 static int ogg_vorbis_trunc(struct ast_filestream *s)
00508 {
00509 ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n");
00510 return -1;
00511 }
00512
00513
00514
00515
00516
00517
00518
00519
00520 static int ogg_vorbis_seek(struct ast_filestream *s, off_t sample_offset, int whence)
00521 {
00522 ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n");
00523 return -1;
00524 }
00525
00526 static off_t ogg_vorbis_tell(struct ast_filestream *s)
00527 {
00528 ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n");
00529 return -1;
00530 }
00531
00532 static const struct ast_format vorbis_f = {
00533 .name = "ogg_vorbis",
00534 .exts = "ogg",
00535 .format = AST_FORMAT_SLINEAR,
00536 .open = ogg_vorbis_open,
00537 .rewrite = ogg_vorbis_rewrite,
00538 .write = ogg_vorbis_write,
00539 .seek = ogg_vorbis_seek,
00540 .trunc = ogg_vorbis_trunc,
00541 .tell = ogg_vorbis_tell,
00542 .read = ogg_vorbis_read,
00543 .close = ogg_vorbis_close,
00544 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00545 .desc_size = sizeof(struct vorbis_desc),
00546 };
00547
00548 static int load_module(void)
00549 {
00550 if (ast_format_register(&vorbis_f))
00551 return AST_MODULE_LOAD_FAILURE;
00552 return AST_MODULE_LOAD_SUCCESS;
00553 }
00554
00555 static int unload_module(void)
00556 {
00557 return ast_format_unregister(vorbis_f.name);
00558 }
00559
00560 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "OGG/Vorbis audio",
00561 .load = load_module,
00562 .unload = unload_module,
00563 .load_pri = AST_MODPRI_APP_DEPEND
00564 );