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