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