OGG/Vorbis streams. More...
#include "asterisk.h"#include <vorbis/codec.h>#include <vorbis/vorbisenc.h>#include <vorbis/vorbisfile.h>#include "asterisk/mod_format.h"#include "asterisk/module.h"
Go to the source code of this file.
Data Structures | |
| struct | ogg_vorbis_desc |
Defines | |
| #define | BLOCK_SIZE 4096 /* used internally in the vorbis routines */ |
| #define | BUF_SIZE (2*SAMPLES_MAX) |
| #define | SAMPLES_MAX 512 |
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 *fs, 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 *fs) |
| Tell the current position in OGG/Vorbis filestream measured in pcms. | |
| static int | ogg_vorbis_trunc (struct ast_filestream *fs) |
| 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 | unload_module (void) |
| static void | write_stream (struct ogg_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_def | vorbis_f |
| #define BLOCK_SIZE 4096 /* used internally in the vorbis routines */ |
Definition at line 56 of file format_ogg_vorbis.c.
| #define BUF_SIZE (2*SAMPLES_MAX) |
Definition at line 54 of file format_ogg_vorbis.c.
Referenced by ogg_vorbis_read().
| #define SAMPLES_MAX 512 |
Definition at line 53 of file format_ogg_vorbis.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 453 of file format_ogg_vorbis.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 453 of file format_ogg_vorbis.c.
| static int load_module | ( | void | ) | [static] |
Definition at line 436 of file format_ogg_vorbis.c.
References ast_format_def_register, ast_format_set(), AST_FORMAT_SLINEAR, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and ast_format_def::format.
{
ast_format_set(&vorbis_f.format, AST_FORMAT_SLINEAR, 0);
if (ast_format_def_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 278 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_filestream::f, ogg_vorbis_desc::ov_f, ogg_vorbis_desc::vd, write_stream(), and ogg_vorbis_desc::writing.
{
struct ogg_vorbis_desc *s = (struct ogg_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);
} else {
/* clear OggVorbis_File handle */
ov_clear(&s->ov_f);
}
}
| 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 109 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_log(), DEFAULT_SAMPLE_RATE, desc, ast_filestream::f, LOG_ERROR, ogg_vorbis_desc::ov_f, and ogg_vorbis_desc::writing.
{
int result;
struct ogg_vorbis_desc *desc = (struct ogg_vorbis_desc *) s->_private;
/* initialize private description block */
memset(desc, 0, sizeof(struct ogg_vorbis_desc));
desc->writing = 0;
/* actually open file */
result = ov_open_callbacks(s->f, &desc->ov_f, NULL, 0, OV_CALLBACKS_NOCLOSE);
if (result != 0) {
ast_log(LOG_ERROR, "Error opening Ogg/Vorbis file stream.\n");
return -1;
}
/* check stream(s) type */
if (desc->ov_f.vi->channels != 1) {
ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
ov_clear(&desc->ov_f);
return -1;
}
if (desc->ov_f.vi->rate != DEFAULT_SAMPLE_RATE) {
ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
ov_clear(&desc->ov_f);
return -1;
}
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 299 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_format_set(), AST_FORMAT_SLINEAR, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_filestream::buf, BUF_SIZE, ast_frame::data, ast_frame::datalen, desc, ast_frame_subclass::format, ast_filestream::fr, ast_frame::frametype, LOG_WARNING, ast_frame::mallocd, ogg_vorbis_desc::ov_f, ast_frame::ptr, ast_frame::samples, ast_frame::subclass, and ogg_vorbis_desc::writing.
{
struct ogg_vorbis_desc *desc = (struct ogg_vorbis_desc *) fs->_private;
int current_bitstream = -10;
char *out_buf;
long bytes_read;
if (desc->writing) {
ast_log(LOG_WARNING, "Reading is not supported on OGG/Vorbis on write files.\n");
return NULL;
}
/* initialize frame */
fs->fr.frametype = AST_FRAME_VOICE;
ast_format_set(&fs->fr.subclass.format, AST_FORMAT_SLINEAR, 0);
fs->fr.mallocd = 0;
AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
out_buf = (char *) (fs->fr.data.ptr); /* SLIN data buffer */
/* read samples from OV interface */
bytes_read = ov_read(
&desc->ov_f,
out_buf, /* Buffer to write data */
BUF_SIZE, /* Size of buffer */
(__BYTE_ORDER == __BIG_ENDIAN), /* Endianes (0 for little) */
2, /* 1 = 8bit, 2 = 16bit */
1, /* 0 = unsigned, 1 = signed */
¤t_bitstream /* Returns the current bitstream section */
);
/* check returned data */
if (bytes_read <= 0) {
/* End of stream */
return NULL;
}
/* Return decoded bytes */
fs->fr.datalen = bytes_read;
fs->fr.samples = bytes_read / 2;
*whennext = fs->fr.samples;
return &fs->fr;
}
| 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 147 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_log(), ast_random(), DEFAULT_SAMPLE_RATE, ogg_vorbis_desc::eos, errno, ast_filestream::f, LOG_ERROR, LOG_WARNING, ogg_vorbis_desc::og, ogg_vorbis_desc::os, ogg_vorbis_desc::vb, ogg_vorbis_desc::vc, ogg_vorbis_desc::vd, ogg_vorbis_desc::vi, ogg_vorbis_desc::writing, and ogg_vorbis_desc::writing_pcm_pos.
{
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
struct ogg_vorbis_desc *tmp = (struct ogg_vorbis_desc *) s->_private;
tmp->writing = 1;
tmp->writing_pcm_pos = 0;
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 * | fs, |
| off_t | sample_offset, | ||
| int | whence | ||
| ) | [static] |
Seek to a specific position in an OGG/Vorbis filestream.
| s | The filestream to take action on. |
| sample_offset | New position for the filestream, measured in 8KHz samples. |
| whence | Location to measure |
Definition at line 382 of file format_ogg_vorbis.c.
References ast_filestream::_private, ast_log(), desc, LOG_WARNING, ogg_vorbis_tell(), ogg_vorbis_desc::ov_f, and ogg_vorbis_desc::writing.
{
int seek_result = -1;
off_t relative_pcm_pos;
struct ogg_vorbis_desc *desc = (struct ogg_vorbis_desc *) fs->_private;
if (desc->writing) {
ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams in writing mode!\n");
return -1;
}
/* ov_pcm_seek support seeking only from begining (SEEK_SET), the rest must be emulated */
switch (whence) {
case SEEK_SET:
seek_result = ov_pcm_seek(&desc->ov_f, sample_offset);
break;
case SEEK_CUR:
if ((relative_pcm_pos = ogg_vorbis_tell(fs)) < 0) {
seek_result = -1;
break;
}
seek_result = ov_pcm_seek(&desc->ov_f, relative_pcm_pos + sample_offset);
break;
case SEEK_END:
if ((relative_pcm_pos = ov_pcm_total(&desc->ov_f, -1)) < 0) {
seek_result = -1;
break;
}
seek_result = ov_pcm_seek(&desc->ov_f, relative_pcm_pos - sample_offset);
break;
default:
ast_log(LOG_WARNING, "Unknown *whence* to seek on OGG/Vorbis streams!\n");
break;
}
/* normalize error value to -1,0 */
return (seek_result == 0) ? 0 : -1;
}
| static off_t ogg_vorbis_tell | ( | struct ast_filestream * | fs | ) | [static] |
Tell the current position in OGG/Vorbis filestream measured in pcms.
| s | The filestream to take action on. |
Definition at line 360 of file format_ogg_vorbis.c.
References ast_filestream::_private, desc, ogg_vorbis_desc::ov_f, ogg_vorbis_desc::writing, and ogg_vorbis_desc::writing_pcm_pos.
Referenced by ogg_vorbis_seek().
{
off_t pos;
struct ogg_vorbis_desc *desc = (struct ogg_vorbis_desc *) fs->_private;
if (desc->writing) {
return desc->writing_pcm_pos;
}
if ((pos = ov_pcm_tell(&desc->ov_f)) < 0) {
return -1;
}
return pos;
}
| static int ogg_vorbis_trunc | ( | struct ast_filestream * | fs | ) | [static] |
Trucate an OGG/Vorbis filestream.
| s | The filestream to truncate. |
Definition at line 349 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 234 of file format_ogg_vorbis.c.
References ast_filestream::_private, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_getformatname(), ast_log(), ast_frame::data, ast_frame::datalen, ast_filestream::f, ast_frame_subclass::format, ast_frame::frametype, ast_format::id, LOG_ERROR, LOG_WARNING, ast_frame::ptr, ast_frame::samples, ast_frame::subclass, ogg_vorbis_desc::vd, write_stream(), ogg_vorbis_desc::writing, and ogg_vorbis_desc::writing_pcm_pos.
{
int i;
float **buffer;
short *data;
struct ogg_vorbis_desc *s = (struct ogg_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.format.id != AST_FORMAT_SLINEAR) {
ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%s)!\n",
ast_getformatname(&f->subclass.format));
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);
s->writing_pcm_pos += f->samples;
return 0;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 444 of file format_ogg_vorbis.c.
References ast_format_def_unregister(), and ast_format_def::name.
{
return ast_format_def_unregister(vorbis_f.name);
}
| static void write_stream | ( | struct ogg_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 202 of file format_ogg_vorbis.c.
References ast_log(), ogg_vorbis_desc::eos, errno, LOG_WARNING, ogg_vorbis_desc::og, ogg_vorbis_desc::op, ogg_vorbis_desc::os, ogg_vorbis_desc::vb, and ogg_vorbis_desc::vd.
Referenced by ast_monitor_stop(), ast_write(), 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 453 of file format_ogg_vorbis.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 453 of file format_ogg_vorbis.c.
struct ast_format_def vorbis_f [static] |
Definition at line 421 of file format_ogg_vorbis.c.