OGG/Vorbis streams. More...
#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_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_format | vorbis_f |
| #define BLOCK_SIZE 4096 |
Definition at line 55 of file format_ogg_vorbis.c.
Referenced by ogg_vorbis_open(), and read_samples().
| #define BUF_SIZE (2*SAMPLES_MAX) |
Definition at line 53 of file format_ogg_vorbis.c.
Referenced by ogg_vorbis_read().
| #define SAMPLES_MAX 160 |
Definition at line 52 of file format_ogg_vorbis.c.
Referenced by ogg_vorbis_read().
| static void __reg_module | ( | void | ) | [static] |
Definition at line 564 of file format_ogg_vorbis.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 564 of file format_ogg_vorbis.c.
| static int load_module | ( | void | ) | [static] |
Definition at line 548 of file format_ogg_vorbis.c.
References ast_format_register, AST_MODULE_LOAD_FAILURE, and AST_MODULE_LOAD_SUCCESS.
{
if (ast_format_register(&vorbis_f))
return AST_MODULE_LOAD_FAILURE;
return AST_MODULE_LOAD_SUCCESS;
}
| static void ogg_vorbis_close | ( | struct ast_filestream * | fs | ) | [static] |
Close a OGG/Vorbis filestream.
| fs | A OGG/Vorbis filestream. |
Definition at line 321 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_filestream::f, vorbis_desc::os, vorbis_desc::oy, vorbis_desc::vb, vorbis_desc::vc, vorbis_desc::vd, vorbis_desc::vi, write_stream(), and vorbis_desc::writing.
{
struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
if (s->writing) {
/* Tell the Vorbis encoder that the stream is finished
* and write out the rest of the data */
vorbis_analysis_wrote(&s->vd, 0);
write_stream(s, fs->f);
}
ogg_stream_clear(&s->os);
vorbis_block_clear(&s->vb);
vorbis_dsp_clear(&s->vd);
vorbis_comment_clear(&s->vc);
vorbis_info_clear(&s->vi);
if (s->writing) {
ogg_sync_clear(&s->oy);
}
}
| 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 82 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_debug, ast_log(), BLOCK_SIZE, DEFAULT_SAMPLE_RATE, ast_filestream::f, LOG_ERROR, vorbis_desc::og, vorbis_desc::op, vorbis_desc::os, vorbis_desc::oy, vorbis_desc::vb, vorbis_desc::vc, vorbis_desc::vd, vorbis_desc::vi, and vorbis_desc::writing.
{
int i;
int bytes;
int result;
char **ptr;
char *buffer;
struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private;
tmp->writing = 0;
ogg_sync_init(&tmp->oy);
buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
ogg_sync_wrote(&tmp->oy, bytes);
result = ogg_sync_pageout(&tmp->oy, &tmp->og);
if (result != 1) {
if(bytes < BLOCK_SIZE) {
ast_log(LOG_ERROR, "Run out of data...\n");
} else {
ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
}
ogg_sync_clear(&tmp->oy);
return -1;
}
ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
vorbis_info_init(&tmp->vi);
vorbis_comment_init(&tmp->vc);
if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) {
ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
error:
ogg_stream_clear(&tmp->os);
vorbis_comment_clear(&tmp->vc);
vorbis_info_clear(&tmp->vi);
ogg_sync_clear(&tmp->oy);
return -1;
}
if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) {
ast_log(LOG_ERROR, "Error reading initial header packet.\n");
goto error;
}
if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) {
ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
goto error;
}
for (i = 0; i < 2 ; ) {
while (i < 2) {
result = ogg_sync_pageout(&tmp->oy, &tmp->og);
if (result == 0)
break;
if (result == 1) {
ogg_stream_pagein(&tmp->os, &tmp->og);
while(i < 2) {
result = ogg_stream_packetout(&tmp->os,&tmp->op);
if(result == 0)
break;
if(result < 0) {
ast_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n");
goto error;
}
vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
i++;
}
}
}
buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
if (bytes == 0 && i < 2) {
ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
goto error;
}
ogg_sync_wrote(&tmp->oy, bytes);
}
for (ptr = tmp->vc.user_comments; *ptr; ptr++)
ast_debug(1, "OGG/Vorbis comment: %s\n", *ptr);
ast_debug(1, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate);
ast_debug(1, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor);
if (tmp->vi.channels != 1) {
ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
goto error;
}
if (tmp->vi.rate != DEFAULT_SAMPLE_RATE) {
ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
vorbis_block_clear(&tmp->vb);
vorbis_dsp_clear(&tmp->vd);
goto error;
}
vorbis_synthesis_init(&tmp->vd, &tmp->vi);
vorbis_block_init(&tmp->vd, &tmp->vb);
return 0;
}
| static struct ast_frame* ogg_vorbis_read | ( | struct ast_filestream * | fs, |
| int * | whennext | ||
| ) | [static, read] |
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 428 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_SIZE, ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, ast_filestream::fr, ast_frame::frametype, len(), LOG_WARNING, ast_frame::mallocd, ast_frame::ptr, read_samples(), ast_frame::samples, SAMPLES_MAX, ast_frame::subclass, vorbis_desc::vd, and vorbis_desc::vi.
{
int clipflag = 0;
int i;
int j;
double accumulator[SAMPLES_MAX];
int val;
int samples_in;
int samples_out = 0;
struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
short *buf; /* SLIN data buffer */
fs->fr.frametype = AST_FRAME_VOICE;
fs->fr.subclass.codec = AST_FORMAT_SLINEAR;
fs->fr.mallocd = 0;
AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
buf = (short *)(fs->fr.data.ptr); /* SLIN data buffer */
while (samples_out != SAMPLES_MAX) {
float **pcm;
int len = SAMPLES_MAX - samples_out;
/* See ifVorbis decoder has some audio data for us ... */
samples_in = read_samples(fs, &pcm);
if (samples_in <= 0)
break;
/* Got some audio data from Vorbis... */
/* Convert the float audio data to 16-bit signed linear */
clipflag = 0;
if (samples_in > len)
samples_in = len;
for (j = 0; j < samples_in; j++)
accumulator[j] = 0.0;
for (i = 0; i < s->vi.channels; i++) {
float *mono = pcm[i];
for (j = 0; j < samples_in; j++)
accumulator[j] += mono[j];
}
for (j = 0; j < samples_in; j++) {
val = accumulator[j] * 32767.0 / s->vi.channels;
if (val > 32767) {
val = 32767;
clipflag = 1;
} else if (val < -32768) {
val = -32768;
clipflag = 1;
}
buf[samples_out + j] = val;
}
if (clipflag)
ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long) (s->vd.sequence));
/* Tell the Vorbis decoder how many samples we actually used. */
vorbis_synthesis_read(&s->vd, samples_in);
samples_out += samples_in;
}
if (samples_out > 0) {
fs->fr.datalen = samples_out * 2;
fs->fr.samples = samples_out;
*whennext = samples_out;
return &fs->fr;
} else {
return NULL;
}
}
| 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 193 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_log(), ast_random(), DEFAULT_SAMPLE_RATE, vorbis_desc::eos, errno, ast_filestream::f, LOG_ERROR, LOG_WARNING, vorbis_desc::og, vorbis_desc::os, vorbis_desc::vb, vorbis_desc::vc, vorbis_desc::vd, vorbis_desc::vi, and vorbis_desc::writing.
{
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private;
tmp->writing = 1;
vorbis_info_init(&tmp->vi);
if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) {
ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n");
return -1;
}
vorbis_comment_init(&tmp->vc);
vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX");
if (comment)
vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment);
vorbis_analysis_init(&tmp->vd, &tmp->vi);
vorbis_block_init(&tmp->vd, &tmp->vb);
ogg_stream_init(&tmp->os, ast_random());
vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm,
&header_code);
ogg_stream_packetin(&tmp->os, &header);
ogg_stream_packetin(&tmp->os, &header_comm);
ogg_stream_packetin(&tmp->os, &header_code);
while (!tmp->eos) {
if (ogg_stream_flush(&tmp->os, &tmp->og) == 0)
break;
if (!fwrite(tmp->og.header, 1, tmp->og.header_len, s->f)) {
ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
}
if (!fwrite(tmp->og.body, 1, tmp->og.body_len, s->f)) {
ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
}
if (ogg_page_eos(&tmp->og))
tmp->eos = 1;
}
return 0;
}
| 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 520 of file format_ogg_vorbis.c.
References ast_log(), and LOG_WARNING.
{
ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n");
return -1;
}
| static off_t ogg_vorbis_tell | ( | struct ast_filestream * | s | ) | [static] |
Definition at line 526 of file format_ogg_vorbis.c.
References ast_log(), and LOG_WARNING.
{
ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n");
return -1;
}
| static int ogg_vorbis_trunc | ( | struct ast_filestream * | s | ) | [static] |
Trucate an OGG/Vorbis filestream.
| s | The filestream to truncate. |
Definition at line 507 of file format_ogg_vorbis.c.
References ast_log(), and LOG_WARNING.
{
ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n");
return -1;
}
| 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 279 of file format_ogg_vorbis.c.
References ast_filestream::_private, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_getformatname(), ast_log(), ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, ast_filestream::f, ast_frame::frametype, LOG_ERROR, LOG_WARNING, ast_frame::ptr, ast_frame::samples, ast_frame::subclass, vorbis_desc::vd, write_stream(), and vorbis_desc::writing.
{
int i;
float **buffer;
short *data;
struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
if (!s->writing) {
ast_log(LOG_ERROR, "This stream is not set up for writing!\n");
return -1;
}
if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1;
}
if (f->subclass.codec != AST_FORMAT_SLINEAR) {
ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%s)!\n",
ast_getformatname(f->subclass.codec));
return -1;
}
if (!f->datalen)
return -1;
data = (short *) f->data.ptr;
buffer = vorbis_analysis_buffer(&s->vd, f->samples);
for (i = 0; i < f->samples; i++)
buffer[0][i] = (double)data[i] / 32768.0;
vorbis_analysis_wrote(&s->vd, f->samples);
write_stream(s, fs->f);
return 0;
}
| 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 349 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_log(), BLOCK_SIZE, vorbis_desc::eos, ast_filestream::f, LOG_WARNING, vorbis_desc::og, vorbis_desc::op, vorbis_desc::os, vorbis_desc::oy, vorbis_desc::vb, and vorbis_desc::vd.
Referenced by ogg_vorbis_read().
{
int samples_in;
int result;
char *buffer;
int bytes;
struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
while (1) {
samples_in = vorbis_synthesis_pcmout(&s->vd, pcm);
if (samples_in > 0) {
return samples_in;
}
/* The Vorbis decoder needs more data... */
/* See ifOGG has any packets in the current page for the Vorbis decoder. */
result = ogg_stream_packetout(&s->os, &s->op);
if (result > 0) {
/* Yes OGG had some more packets for the Vorbis decoder. */
if (vorbis_synthesis(&s->vb, &s->op) == 0) {
vorbis_synthesis_blockin(&s->vd, &s->vb);
}
continue;
}
if (result < 0)
ast_log(LOG_WARNING,
"Corrupt or missing data at this page position; continuing...\n");
/* No more packets left in the current page... */
if (s->eos) {
/* No more pages left in the stream */
return -1;
}
while (!s->eos) {
/* See ifOGG has any pages in it's internal buffers */
result = ogg_sync_pageout(&s->oy, &s->og);
if (result > 0) {
/* Yes, OGG has more pages in it's internal buffers,
add the page to the stream state */
result = ogg_stream_pagein(&s->os, &s->og);
if (result == 0) {
/* Yes, got a new,valid page */
if (ogg_page_eos(&s->og)) {
s->eos = 1;
}
break;
}
ast_log(LOG_WARNING,
"Invalid page in the bitstream; continuing...\n");
}
if (result < 0)
ast_log(LOG_WARNING,
"Corrupt or missing data in bitstream; continuing...\n");
/* No, we need to read more data from the file descrptor */
/* get a buffer from OGG to read the data into */
buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
/* read more data from the file descriptor */
bytes = fread(buffer, 1, BLOCK_SIZE, fs->f);
/* Tell OGG how many bytes we actually read into the buffer */
ogg_sync_wrote(&s->oy, bytes);
if (bytes == 0) {
s->eos = 1;
}
}
}
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 555 of file format_ogg_vorbis.c.
References ast_format_unregister(), and ast_format::name.
{
return ast_format_unregister(vorbis_f.name);
}
| 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 247 of file format_ogg_vorbis.c.
References ast_log(), vorbis_desc::eos, errno, LOG_WARNING, vorbis_desc::og, vorbis_desc::op, vorbis_desc::os, vorbis_desc::vb, and vorbis_desc::vd.
Referenced by ogg_vorbis_close(), and ogg_vorbis_write().
{
while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
vorbis_analysis(&s->vb, NULL);
vorbis_bitrate_addblock(&s->vb);
while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) {
ogg_stream_packetin(&s->os, &s->op);
while (!s->eos) {
if (ogg_stream_pageout(&s->os, &s->og) == 0) {
break;
}
if (!fwrite(s->og.header, 1, s->og.header_len, f)) {
ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
}
if (!fwrite(s->og.body, 1, s->og.body_len, f)) {
ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
}
if (ogg_page_eos(&s->og)) {
s->eos = 1;
}
}
}
}
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND } [static] |
Definition at line 564 of file format_ogg_vorbis.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 564 of file format_ogg_vorbis.c.
struct ast_format vorbis_f [static] |
Definition at line 532 of file format_ogg_vorbis.c.