#include "asterisk.h"
#include <vorbis/codec.h>
#include <vorbis/vorbisenc.h>
#include "asterisk/mod_format.h"
#include "asterisk/module.h"
Go to the source code of this file.
Data Structures | |
struct | vorbis_desc |
Defines | |
#define | BLOCK_SIZE 4096 |
#define | BUF_SIZE (2*SAMPLES_MAX) |
#define | SAMPLES_MAX 160 |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | load_module (void) |
static void | ogg_vorbis_close (struct ast_filestream *fs) |
Close a OGG/Vorbis filestream. | |
static int | ogg_vorbis_open (struct ast_filestream *s) |
Create a new OGG/Vorbis filestream and set it up for reading. | |
static struct ast_frame * | ogg_vorbis_read (struct ast_filestream *fs, int *whennext) |
Read a frame full of audio data from the filestream. | |
static int | ogg_vorbis_rewrite (struct ast_filestream *s, const char *comment) |
Create a new OGG/Vorbis filestream and set it up for writing. | |
static int | ogg_vorbis_seek (struct ast_filestream *s, off_t sample_offset, int whence) |
Seek to a specific position in an OGG/Vorbis filestream. | |
static off_t | ogg_vorbis_tell (struct ast_filestream *s) |
static int | ogg_vorbis_trunc (struct ast_filestream *s) |
Trucate an OGG/Vorbis filestream. | |
static int | ogg_vorbis_write (struct ast_filestream *fs, struct ast_frame *f) |
Write audio data from a frame to an OGG/Vorbis filestream. | |
static int | read_samples (struct ast_filestream *fs, float ***pcm) |
Get audio data. | |
static int | unload_module (void) |
static void | write_stream (struct vorbis_desc *s, FILE *f) |
Write out any pending encoded data. | |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "OGG/Vorbis audio" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_format | vorbis_f |
Definition in file format_ogg_vorbis.c.
#define BLOCK_SIZE 4096 |
Definition at line 54 of file format_ogg_vorbis.c.
Referenced by ogg_vorbis_open(), and read_samples().
#define BUF_SIZE (2*SAMPLES_MAX) |
Definition at line 52 of file format_ogg_vorbis.c.
#define SAMPLES_MAX 160 |
static void __reg_module | ( | void | ) | [static] |
Definition at line 559 of file format_ogg_vorbis.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 559 of file format_ogg_vorbis.c.
static int load_module | ( | void | ) | [static] |
Definition at line 547 of file format_ogg_vorbis.c.
References ast_format_register, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and vorbis_f.
00548 { 00549 if (ast_format_register(&vorbis_f)) 00550 return AST_MODULE_LOAD_FAILURE; 00551 return AST_MODULE_LOAD_SUCCESS; 00552 }
static void ogg_vorbis_close | ( | struct ast_filestream * | fs | ) | [static] |
Close a OGG/Vorbis filestream.
fs | A OGG/Vorbis filestream. |
Definition at line 320 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_filestream::f, s, and write_stream().
00321 { 00322 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private; 00323 00324 if (s->writing) { 00325 /* Tell the Vorbis encoder that the stream is finished 00326 * and write out the rest of the data */ 00327 vorbis_analysis_wrote(&s->vd, 0); 00328 write_stream(s, fs->f); 00329 } 00330 00331 ogg_stream_clear(&s->os); 00332 vorbis_block_clear(&s->vb); 00333 vorbis_dsp_clear(&s->vd); 00334 vorbis_comment_clear(&s->vc); 00335 vorbis_info_clear(&s->vi); 00336 00337 if (s->writing) { 00338 ogg_sync_clear(&s->oy); 00339 } 00340 }
static int ogg_vorbis_open | ( | struct ast_filestream * | s | ) | [static] |
Create a new OGG/Vorbis filestream and set it up for reading.
s | File that points to on disk storage of the OGG/Vorbis data. |
Definition at line 81 of file format_ogg_vorbis.c.
References ast_log(), BLOCK_SIZE, LOG_ERROR, vorbis_desc::og, vorbis_desc::op, vorbis_desc::os, vorbis_desc::oy, s, vorbis_desc::vc, vorbis_desc::vi, and vorbis_desc::writing.
00082 { 00083 int i; 00084 int bytes; 00085 int result; 00086 char **ptr; 00087 char *buffer; 00088 struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private; 00089 00090 tmp->writing = 0; 00091 00092 ogg_sync_init(&tmp->oy); 00093 00094 buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); 00095 bytes = fread(buffer, 1, BLOCK_SIZE, s->f); 00096 ogg_sync_wrote(&tmp->oy, bytes); 00097 00098 result = ogg_sync_pageout(&tmp->oy, &tmp->og); 00099 if (result != 1) { 00100 if(bytes < BLOCK_SIZE) { 00101 ast_log(LOG_ERROR, "Run out of data...\n"); 00102 } else { 00103 ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); 00104 } 00105 ogg_sync_clear(&tmp->oy); 00106 return -1; 00107 } 00108 00109 ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og)); 00110 vorbis_info_init(&tmp->vi); 00111 vorbis_comment_init(&tmp->vc); 00112 00113 if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { 00114 ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); 00115 error: 00116 ogg_stream_clear(&tmp->os); 00117 vorbis_comment_clear(&tmp->vc); 00118 vorbis_info_clear(&tmp->vi); 00119 ogg_sync_clear(&tmp->oy); 00120 return -1; 00121 } 00122 00123 if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { 00124 ast_log(LOG_ERROR, "Error reading initial header packet.\n"); 00125 goto error; 00126 } 00127 00128 if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { 00129 ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n"); 00130 goto error; 00131 } 00132 00133 for (i = 0; i < 2 ; ) { 00134 while (i < 2) { 00135 result = ogg_sync_pageout(&tmp->oy, &tmp->og); 00136 if (result == 0) 00137 break; 00138 if (result == 1) { 00139 ogg_stream_pagein(&tmp->os, &tmp->og); 00140 while(i < 2) { 00141 result = ogg_stream_packetout(&tmp->os,&tmp->op); 00142 if(result == 0) 00143 break; 00144 if(result < 0) { 00145 ast_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n"); 00146 goto error; 00147 } 00148 vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op); 00149 i++; 00150 } 00151 } 00152 } 00153 00154 buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); 00155 bytes = fread(buffer, 1, BLOCK_SIZE, s->f); 00156 if (bytes == 0 && i < 2) { 00157 ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n"); 00158 goto error; 00159 } 00160 ogg_sync_wrote(&tmp->oy, bytes); 00161 } 00162 00163 for (ptr = tmp->vc.user_comments; *ptr; ptr++) 00164 ast_debug(1, "OGG/Vorbis comment: %s\n", *ptr); 00165 ast_debug(1, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate); 00166 ast_debug(1, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor); 00167 00168 if (tmp->vi.channels != 1) { 00169 ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n"); 00170 goto error; 00171 } 00172 00173 if (tmp->vi.rate != DEFAULT_SAMPLE_RATE) { 00174 ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n"); 00175 vorbis_block_clear(&tmp->vb); 00176 vorbis_dsp_clear(&tmp->vd); 00177 goto error; 00178 } 00179 00180 vorbis_synthesis_init(&tmp->vd, &tmp->vi); 00181 vorbis_block_init(&tmp->vd, &tmp->vb); 00182 00183 return 0; 00184 }
static struct ast_frame* ogg_vorbis_read | ( | struct ast_filestream * | fs, | |
int * | whennext | |||
) | [static] |
Read a frame full of audio data from the filestream.
fs | The filestream. | |
whennext | Number of sample times to schedule the next call. |
Definition at line 427 of file format_ogg_vorbis.c.
References ast_filestream::_private, AST_FORMAT_SLINEAR, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_filestream::buf, buf, BUF_SIZE, ast_frame::data, ast_frame::datalen, ast_filestream::fr, ast_frame::frametype, len(), LOG_WARNING, ast_frame::mallocd, read_samples(), s, ast_frame::samples, SAMPLES_MAX, and ast_frame::subclass.
00429 { 00430 int clipflag = 0; 00431 int i; 00432 int j; 00433 double accumulator[SAMPLES_MAX]; 00434 int val; 00435 int samples_in; 00436 int samples_out = 0; 00437 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private; 00438 short *buf; /* SLIN data buffer */ 00439 00440 fs->fr.frametype = AST_FRAME_VOICE; 00441 fs->fr.subclass = AST_FORMAT_SLINEAR; 00442 fs->fr.mallocd = 0; 00443 AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); 00444 buf = (short *)(fs->fr.data); /* SLIN data buffer */ 00445 00446 while (samples_out != SAMPLES_MAX) { 00447 float **pcm; 00448 int len = SAMPLES_MAX - samples_out; 00449 00450 /* See ifVorbis decoder has some audio data for us ... */ 00451 samples_in = read_samples(fs, &pcm); 00452 if (samples_in <= 0) 00453 break; 00454 00455 /* Got some audio data from Vorbis... */ 00456 /* Convert the float audio data to 16-bit signed linear */ 00457 00458 clipflag = 0; 00459 if (samples_in > len) 00460 samples_in = len; 00461 for (j = 0; j < samples_in; j++) 00462 accumulator[j] = 0.0; 00463 00464 for (i = 0; i < s->vi.channels; i++) { 00465 float *mono = pcm[i]; 00466 for (j = 0; j < samples_in; j++) 00467 accumulator[j] += mono[j]; 00468 } 00469 00470 for (j = 0; j < samples_in; j++) { 00471 val = accumulator[j] * 32767.0 / s->vi.channels; 00472 if (val > 32767) { 00473 val = 32767; 00474 clipflag = 1; 00475 } else if (val < -32768) { 00476 val = -32768; 00477 clipflag = 1; 00478 } 00479 buf[samples_out + j] = val; 00480 } 00481 00482 if (clipflag) 00483 ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long) (s->vd.sequence)); 00484 /* Tell the Vorbis decoder how many samples we actually used. */ 00485 vorbis_synthesis_read(&s->vd, samples_in); 00486 samples_out += samples_in; 00487 } 00488 00489 if (samples_out > 0) { 00490 fs->fr.datalen = samples_out * 2; 00491 fs->fr.samples = samples_out; 00492 *whennext = samples_out; 00493 00494 return &fs->fr; 00495 } else { 00496 return NULL; 00497 } 00498 }
static int ogg_vorbis_rewrite | ( | struct ast_filestream * | s, | |
const char * | comment | |||
) | [static] |
Create a new OGG/Vorbis filestream and set it up for writing.
s | File pointer that points to on-disk storage. | |
comment | Comment that should be embedded in the OGG/Vorbis file. |
Definition at line 192 of file format_ogg_vorbis.c.
References ast_log(), ast_random(), DEFAULT_SAMPLE_RATE, vorbis_desc::eos, errno, LOG_ERROR, LOG_WARNING, vorbis_desc::og, vorbis_desc::os, s, vorbis_desc::vb, vorbis_desc::vc, vorbis_desc::vd, vorbis_desc::vi, and vorbis_desc::writing.
00194 { 00195 ogg_packet header; 00196 ogg_packet header_comm; 00197 ogg_packet header_code; 00198 struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private; 00199 00200 tmp->writing = 1; 00201 00202 vorbis_info_init(&tmp->vi); 00203 00204 if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) { 00205 ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n"); 00206 return -1; 00207 } 00208 00209 vorbis_comment_init(&tmp->vc); 00210 vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX"); 00211 if (comment) 00212 vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment); 00213 00214 vorbis_analysis_init(&tmp->vd, &tmp->vi); 00215 vorbis_block_init(&tmp->vd, &tmp->vb); 00216 00217 ogg_stream_init(&tmp->os, ast_random()); 00218 00219 vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm, 00220 &header_code); 00221 ogg_stream_packetin(&tmp->os, &header); 00222 ogg_stream_packetin(&tmp->os, &header_comm); 00223 ogg_stream_packetin(&tmp->os, &header_code); 00224 00225 while (!tmp->eos) { 00226 if (ogg_stream_flush(&tmp->os, &tmp->og) == 0) 00227 break; 00228 if (!fwrite(tmp->og.header, 1, tmp->og.header_len, s->f)) { 00229 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00230 } 00231 if (!fwrite(tmp->og.body, 1, tmp->og.body_len, s->f)) { 00232 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00233 } 00234 if (ogg_page_eos(&tmp->og)) 00235 tmp->eos = 1; 00236 } 00237 00238 return 0; 00239 }
static int ogg_vorbis_seek | ( | struct ast_filestream * | s, | |
off_t | sample_offset, | |||
int | whence | |||
) | [static] |
Seek to a specific position in an OGG/Vorbis filestream.
s | The filestream to truncate. | |
sample_offset | New position for the filestream, measured in 8KHz samples. | |
whence | Location to measure |
Definition at line 519 of file format_ogg_vorbis.c.
References ast_log(), and LOG_WARNING.
00520 { 00521 ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n"); 00522 return -1; 00523 }
static off_t ogg_vorbis_tell | ( | struct ast_filestream * | s | ) | [static] |
Definition at line 525 of file format_ogg_vorbis.c.
References ast_log(), and LOG_WARNING.
00526 { 00527 ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n"); 00528 return -1; 00529 }
static int ogg_vorbis_trunc | ( | struct ast_filestream * | s | ) | [static] |
Trucate an OGG/Vorbis filestream.
s | The filestream to truncate. |
Definition at line 506 of file format_ogg_vorbis.c.
References ast_log(), and LOG_WARNING.
00507 { 00508 ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n"); 00509 return -1; 00510 }
static int ogg_vorbis_write | ( | struct ast_filestream * | fs, | |
struct ast_frame * | f | |||
) | [static] |
Write audio data from a frame to an OGG/Vorbis filestream.
fs | An OGG/Vorbis filestream. | |
f | A frame containing audio to be written to the filestream. |
Definition at line 278 of file format_ogg_vorbis.c.
References ast_filestream::_private, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_filestream::f, f, LOG_ERROR, LOG_WARNING, s, and write_stream().
00279 { 00280 int i; 00281 float **buffer; 00282 short *data; 00283 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private; 00284 00285 if (!s->writing) { 00286 ast_log(LOG_ERROR, "This stream is not set up for writing!\n"); 00287 return -1; 00288 } 00289 00290 if (f->frametype != AST_FRAME_VOICE) { 00291 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); 00292 return -1; 00293 } 00294 if (f->subclass != AST_FORMAT_SLINEAR) { 00295 ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%d)!\n", 00296 f->subclass); 00297 return -1; 00298 } 00299 if (!f->datalen) 00300 return -1; 00301 00302 data = (short *) f->data; 00303 00304 buffer = vorbis_analysis_buffer(&s->vd, f->samples); 00305 00306 for (i = 0; i < f->samples; i++) 00307 buffer[0][i] = (double)data[i] / 32768.0; 00308 00309 vorbis_analysis_wrote(&s->vd, f->samples); 00310 00311 write_stream(s, fs->f); 00312 00313 return 0; 00314 }
static int read_samples | ( | struct ast_filestream * | fs, | |
float *** | pcm | |||
) | [static] |
Get audio data.
fs | An OGG/Vorbis filestream. | |
pcm | Pointer to a buffere to store audio data in. |
Definition at line 348 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_log(), BLOCK_SIZE, ast_filestream::f, LOG_WARNING, and s.
Referenced by ogg_vorbis_read().
00349 { 00350 int samples_in; 00351 int result; 00352 char *buffer; 00353 int bytes; 00354 struct vorbis_desc *s = (struct vorbis_desc *)fs->_private; 00355 00356 while (1) { 00357 samples_in = vorbis_synthesis_pcmout(&s->vd, pcm); 00358 if (samples_in > 0) { 00359 return samples_in; 00360 } 00361 00362 /* The Vorbis decoder needs more data... */ 00363 /* See ifOGG has any packets in the current page for the Vorbis decoder. */ 00364 result = ogg_stream_packetout(&s->os, &s->op); 00365 if (result > 0) { 00366 /* Yes OGG had some more packets for the Vorbis decoder. */ 00367 if (vorbis_synthesis(&s->vb, &s->op) == 0) { 00368 vorbis_synthesis_blockin(&s->vd, &s->vb); 00369 } 00370 00371 continue; 00372 } 00373 00374 if (result < 0) 00375 ast_log(LOG_WARNING, 00376 "Corrupt or missing data at this page position; continuing...\n"); 00377 00378 /* No more packets left in the current page... */ 00379 00380 if (s->eos) { 00381 /* No more pages left in the stream */ 00382 return -1; 00383 } 00384 00385 while (!s->eos) { 00386 /* See ifOGG has any pages in it's internal buffers */ 00387 result = ogg_sync_pageout(&s->oy, &s->og); 00388 if (result > 0) { 00389 /* Yes, OGG has more pages in it's internal buffers, 00390 add the page to the stream state */ 00391 result = ogg_stream_pagein(&s->os, &s->og); 00392 if (result == 0) { 00393 /* Yes, got a new,valid page */ 00394 if (ogg_page_eos(&s->og)) { 00395 s->eos = 1; 00396 } 00397 break; 00398 } 00399 ast_log(LOG_WARNING, 00400 "Invalid page in the bitstream; continuing...\n"); 00401 } 00402 00403 if (result < 0) 00404 ast_log(LOG_WARNING, 00405 "Corrupt or missing data in bitstream; continuing...\n"); 00406 00407 /* No, we need to read more data from the file descrptor */ 00408 /* get a buffer from OGG to read the data into */ 00409 buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); 00410 /* read more data from the file descriptor */ 00411 bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); 00412 /* Tell OGG how many bytes we actually read into the buffer */ 00413 ogg_sync_wrote(&s->oy, bytes); 00414 if (bytes == 0) { 00415 s->eos = 1; 00416 } 00417 } 00418 } 00419 }
static int unload_module | ( | void | ) | [static] |
Definition at line 554 of file format_ogg_vorbis.c.
References ast_format_unregister(), ast_format::name, and vorbis_f.
00555 { 00556 return ast_format_unregister(vorbis_f.name); 00557 }
static void write_stream | ( | struct vorbis_desc * | s, | |
FILE * | f | |||
) | [static] |
Write out any pending encoded data.
s | An OGG/Vorbis filestream. | |
f | The file to write to. |
Definition at line 246 of file format_ogg_vorbis.c.
References ast_log(), errno, LOG_WARNING, and s.
Referenced by ogg_vorbis_close(), and ogg_vorbis_write().
00247 { 00248 while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) { 00249 vorbis_analysis(&s->vb, NULL); 00250 vorbis_bitrate_addblock(&s->vb); 00251 00252 while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) { 00253 ogg_stream_packetin(&s->os, &s->op); 00254 while (!s->eos) { 00255 if (ogg_stream_pageout(&s->os, &s->og) == 0) { 00256 break; 00257 } 00258 if (!fwrite(s->og.header, 1, s->og.header_len, f)) { 00259 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00260 } 00261 if (!fwrite(s->og.body, 1, s->og.body_len, f)) { 00262 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00263 } 00264 if (ogg_page_eos(&s->og)) { 00265 s->eos = 1; 00266 } 00267 } 00268 } 00269 } 00270 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "OGG/Vorbis audio" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 559 of file format_ogg_vorbis.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 559 of file format_ogg_vorbis.c.
struct ast_format vorbis_f [static] |
Definition at line 531 of file format_ogg_vorbis.c.
Referenced by load_module(), and unload_module().