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: 233782 $")
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 if (!fwrite(tmp->og.header, 1, tmp->og.header_len, s->f)) {
00243 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00244 }
00245 if (!fwrite(tmp->og.body, 1, tmp->og.body_len, s->f)) {
00246 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00247 }
00248 if (ogg_page_eos(&tmp->og))
00249 tmp->eos = 1;
00250 }
00251
00252 return 0;
00253 }
00254
00255
00256
00257
00258
00259
00260 static void write_stream(struct vorbis_desc *s, FILE *f)
00261 {
00262 while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
00263 vorbis_analysis(&s->vb, NULL);
00264 vorbis_bitrate_addblock(&s->vb);
00265
00266 while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) {
00267 ogg_stream_packetin(&s->os, &s->op);
00268 while (!s->eos) {
00269 if (ogg_stream_pageout(&s->os, &s->og) == 0) {
00270 break;
00271 }
00272 if (!fwrite(s->og.header, 1, s->og.header_len, f)) {
00273 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00274 }
00275 if (!fwrite(s->og.body, 1, s->og.body_len, f)) {
00276 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00277 }
00278 if (ogg_page_eos(&s->og)) {
00279 s->eos = 1;
00280 }
00281 }
00282 }
00283 }
00284 }
00285
00286
00287
00288
00289
00290
00291
00292 static int ogg_vorbis_write(struct ast_filestream *fs, struct ast_frame *f)
00293 {
00294 int i;
00295 float **buffer;
00296 short *data;
00297 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
00298
00299 if (!s->writing) {
00300 ast_log(LOG_ERROR, "This stream is not set up for writing!\n");
00301 return -1;
00302 }
00303
00304 if (f->frametype != AST_FRAME_VOICE) {
00305 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00306 return -1;
00307 }
00308 if (f->subclass != AST_FORMAT_SLINEAR) {
00309 ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%d)!\n",
00310 f->subclass);
00311 return -1;
00312 }
00313 if (!f->datalen)
00314 return -1;
00315
00316 data = (short *) f->data;
00317
00318 buffer = vorbis_analysis_buffer(&s->vd, f->samples);
00319
00320 for (i = 0; i < f->samples; i++)
00321 buffer[0][i] = (double)data[i] / 32768.0;
00322
00323 vorbis_analysis_wrote(&s->vd, f->samples);
00324
00325 write_stream(s, fs->f);
00326
00327 return 0;
00328 }
00329
00330
00331
00332
00333
00334 static void ogg_vorbis_close(struct ast_filestream *fs)
00335 {
00336 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
00337
00338 if (s->writing) {
00339
00340
00341 vorbis_analysis_wrote(&s->vd, 0);
00342 write_stream(s, fs->f);
00343 }
00344
00345 ogg_stream_clear(&s->os);
00346 vorbis_block_clear(&s->vb);
00347 vorbis_dsp_clear(&s->vd);
00348 vorbis_comment_clear(&s->vc);
00349 vorbis_info_clear(&s->vi);
00350
00351 if (s->writing) {
00352 ogg_sync_clear(&s->oy);
00353 }
00354 }
00355
00356
00357
00358
00359
00360
00361
00362 static int read_samples(struct ast_filestream *fs, float ***pcm)
00363 {
00364 int samples_in;
00365 int result;
00366 char *buffer;
00367 int bytes;
00368 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
00369
00370 while (1) {
00371 samples_in = vorbis_synthesis_pcmout(&s->vd, pcm);
00372 if (samples_in > 0) {
00373 return samples_in;
00374 }
00375
00376
00377
00378 result = ogg_stream_packetout(&s->os, &s->op);
00379 if (result > 0) {
00380
00381 if (vorbis_synthesis(&s->vb, &s->op) == 0) {
00382 vorbis_synthesis_blockin(&s->vd, &s->vb);
00383 }
00384
00385 continue;
00386 }
00387
00388 if (result < 0)
00389 ast_log(LOG_WARNING,
00390 "Corrupt or missing data at this page position; continuing...\n");
00391
00392
00393
00394 if (s->eos) {
00395
00396 return -1;
00397 }
00398
00399 while (!s->eos) {
00400
00401 result = ogg_sync_pageout(&s->oy, &s->og);
00402 if (result > 0) {
00403
00404
00405 result = ogg_stream_pagein(&s->os, &s->og);
00406 if (result == 0) {
00407
00408 if (ogg_page_eos(&s->og)) {
00409 s->eos = 1;
00410 }
00411 break;
00412 }
00413 ast_log(LOG_WARNING,
00414 "Invalid page in the bitstream; continuing...\n");
00415 }
00416
00417 if (result < 0)
00418 ast_log(LOG_WARNING,
00419 "Corrupt or missing data in bitstream; continuing...\n");
00420
00421
00422
00423 buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
00424
00425 bytes = fread(buffer, 1, BLOCK_SIZE, fs->f);
00426
00427 ogg_sync_wrote(&s->oy, bytes);
00428 if (bytes == 0) {
00429 s->eos = 1;
00430 }
00431 }
00432 }
00433 }
00434
00435
00436
00437
00438
00439
00440
00441 static struct ast_frame *ogg_vorbis_read(struct ast_filestream *fs,
00442 int *whennext)
00443 {
00444 int clipflag = 0;
00445 int i;
00446 int j;
00447 double accumulator[SAMPLES_MAX];
00448 int val;
00449 int samples_in;
00450 int samples_out = 0;
00451 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
00452 short *buf;
00453
00454 fs->fr.frametype = AST_FRAME_VOICE;
00455 fs->fr.subclass = AST_FORMAT_SLINEAR;
00456 fs->fr.mallocd = 0;
00457 AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
00458 buf = (short *)(fs->fr.data);
00459
00460 while (samples_out != SAMPLES_MAX) {
00461 float **pcm;
00462 int len = SAMPLES_MAX - samples_out;
00463
00464
00465 samples_in = read_samples(fs, &pcm);
00466 if (samples_in <= 0)
00467 break;
00468
00469
00470
00471
00472 clipflag = 0;
00473 if (samples_in > len)
00474 samples_in = len;
00475 for (j = 0; j < samples_in; j++)
00476 accumulator[j] = 0.0;
00477
00478 for (i = 0; i < s->vi.channels; i++) {
00479 float *mono = pcm[i];
00480 for (j = 0; j < samples_in; j++)
00481 accumulator[j] += mono[j];
00482 }
00483
00484 for (j = 0; j < samples_in; j++) {
00485 val = accumulator[j] * 32767.0 / s->vi.channels;
00486 if (val > 32767) {
00487 val = 32767;
00488 clipflag = 1;
00489 } else if (val < -32768) {
00490 val = -32768;
00491 clipflag = 1;
00492 }
00493 buf[samples_out + j] = val;
00494 }
00495
00496 if (clipflag)
00497 ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long) (s->vd.sequence));
00498
00499 vorbis_synthesis_read(&s->vd, samples_in);
00500 samples_out += samples_in;
00501 }
00502
00503 if (samples_out > 0) {
00504 fs->fr.datalen = samples_out * 2;
00505 fs->fr.samples = samples_out;
00506 *whennext = samples_out;
00507
00508 return &fs->fr;
00509 } else {
00510 return NULL;
00511 }
00512 }
00513
00514
00515
00516
00517
00518
00519
00520 static int ogg_vorbis_trunc(struct ast_filestream *s)
00521 {
00522 ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n");
00523 return -1;
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533 static int ogg_vorbis_seek(struct ast_filestream *s, off_t sample_offset, int whence)
00534 {
00535 ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n");
00536 return -1;
00537 }
00538
00539 static off_t ogg_vorbis_tell(struct ast_filestream *s)
00540 {
00541 ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n");
00542 return -1;
00543 }
00544
00545 static const struct ast_format vorbis_f = {
00546 .name = "ogg_vorbis",
00547 .exts = "ogg",
00548 .format = AST_FORMAT_SLINEAR,
00549 .open = ogg_vorbis_open,
00550 .rewrite = ogg_vorbis_rewrite,
00551 .write = ogg_vorbis_write,
00552 .seek = ogg_vorbis_seek,
00553 .trunc = ogg_vorbis_trunc,
00554 .tell = ogg_vorbis_tell,
00555 .read = ogg_vorbis_read,
00556 .close = ogg_vorbis_close,
00557 .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00558 .desc_size = sizeof(struct vorbis_desc),
00559 };
00560
00561 static int load_module(void)
00562 {
00563 return ast_format_register(&vorbis_f);
00564 }
00565
00566 static int unload_module(void)
00567 {
00568 return ast_format_unregister(vorbis_f.name);
00569 }
00570
00571 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "OGG/Vorbis audio",
00572 .load = load_module,
00573 .unload = unload_module,
00574 );
00575