37 #include <vorbis/codec.h>
38 #include <vorbis/vorbisenc.h>
39 #include <vorbis/vorbisfile.h>
53 #define SAMPLES_MAX 512
54 #define BUF_SIZE (2*SAMPLES_MAX)
56 #define BLOCK_SIZE 4096
83 #if !defined(HAVE_VORBIS_OPEN_CALLBACKS)
88 static int _ov_header_fseek_wrap(FILE *f, ogg_int64_t off,
int whence)
93 return fseek(f, off, whence);
96 static ov_callbacks OV_CALLBACKS_NOCLOSE = {
97 (size_t (*)(
void *, size_t, size_t,
void *)) fread,
98 (int (*)(
void *, ogg_int64_t, int)) _ov_header_fseek_wrap,
99 (
int (*)(
void *)) NULL,
100 (
long (*)(
void *)) ftell
119 result = ov_open_callbacks(s->f, &desc->ov_f, NULL, 0, OV_CALLBACKS_NOCLOSE);
121 ast_log(LOG_ERROR,
"Error opening Ogg/Vorbis file stream.\n");
126 if (desc->ov_f.vi->channels != 1) {
127 ast_log(LOG_ERROR,
"Only monophonic OGG/Vorbis files are currently supported!\n");
128 ov_clear(&desc->ov_f);
132 if (desc->ov_f.vi->rate != DEFAULT_SAMPLE_RATE) {
133 ast_log(LOG_ERROR,
"Only 8000Hz OGG/Vorbis files are currently supported!\n");
134 ov_clear(&desc->ov_f);
151 ogg_packet header_comm;
152 ogg_packet header_code;
158 vorbis_info_init(&tmp->vi);
160 if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) {
161 ast_log(LOG_ERROR,
"Unable to initialize Vorbis encoder!\n");
162 vorbis_info_clear(&tmp->vi);
166 vorbis_comment_init(&tmp->vc);
167 vorbis_comment_add_tag(&tmp->vc,
"ENCODER",
"Asterisk PBX");
169 vorbis_comment_add_tag(&tmp->vc,
"COMMENT", (
char *) comment);
171 vorbis_analysis_init(&tmp->vd, &tmp->vi);
172 vorbis_block_init(&tmp->vd, &tmp->vb);
174 ogg_stream_init(&tmp->os, ast_random());
176 vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm,
178 ogg_stream_packetin(&tmp->os, &header);
179 ogg_stream_packetin(&tmp->os, &header_comm);
180 ogg_stream_packetin(&tmp->os, &header_code);
183 if (ogg_stream_flush(&tmp->os, &tmp->og) == 0)
185 if (fwrite(tmp->og.header, 1, tmp->og.header_len, s->f) != tmp->og.header_len) {
186 ast_log(LOG_WARNING,
"fwrite() failed: %s\n", strerror(errno));
188 if (fwrite(tmp->og.body, 1, tmp->og.body_len, s->f) != tmp->og.body_len) {
189 ast_log(LOG_WARNING,
"fwrite() failed: %s\n", strerror(errno));
191 if (ogg_page_eos(&tmp->og))
205 while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
206 vorbis_analysis(&s->vb, NULL);
207 vorbis_bitrate_addblock(&s->vb);
209 while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) {
210 ogg_stream_packetin(&s->os, &s->op);
212 if (ogg_stream_pageout(&s->os, &s->og) == 0) {
215 if (fwrite(s->og.header, 1, s->og.header_len, f) != s->og.header_len) {
216 ast_log(LOG_WARNING,
"fwrite() failed: %s\n", strerror(errno));
218 if (fwrite(s->og.body, 1, s->og.body_len, f) != s->og.body_len) {
219 ast_log(LOG_WARNING,
"fwrite() failed: %s\n", strerror(errno));
221 if (ogg_page_eos(&s->og)) {
243 ast_log(LOG_ERROR,
"This stream is not set up for writing!\n");
249 data = (
short *) f->
data.ptr;
251 buffer = vorbis_analysis_buffer(&s->vd, f->
samples);
253 for (i = 0; i < f->
samples; i++)
254 buffer[0][i] = (
double)data[i] / 32768.0;
256 vorbis_analysis_wrote(&s->vd, f->
samples);
276 vorbis_analysis_wrote(&s->vd, 0);
280 ogg_stream_clear(&s->os);
281 vorbis_block_clear(&s->vb);
282 vorbis_dsp_clear(&s->vd);
283 vorbis_comment_clear(&s->vc);
284 vorbis_info_clear(&s->vi);
301 int current_bitstream = -10;
306 ast_log(LOG_WARNING,
"Reading is not supported on OGG/Vorbis on write files.\n");
312 out_buf = (
char *) (fs->
fr.
data.ptr);
315 bytes_read = ov_read(
319 (__BYTE_ORDER == __BIG_ENDIAN),
326 if (bytes_read <= 0) {
346 ast_log(LOG_WARNING,
"Truncation is not supported on OGG/Vorbis streams!\n");
364 if ((pos = ov_pcm_tell(&desc->ov_f)) < 0) {
379 int seek_result = -1;
380 off_t relative_pcm_pos;
384 ast_log(LOG_WARNING,
"Seeking is not supported on OGG/Vorbis streams in writing mode!\n");
391 seek_result = ov_pcm_seek(&desc->ov_f, sample_offset);
398 seek_result = ov_pcm_seek(&desc->ov_f, relative_pcm_pos + sample_offset);
401 if ((relative_pcm_pos = ov_pcm_total(&desc->ov_f, -1)) < 0) {
405 seek_result = ov_pcm_seek(&desc->ov_f, relative_pcm_pos - sample_offset);
408 ast_log(LOG_WARNING,
"Unknown *whence* to seek on OGG/Vorbis streams!\n");
413 return (seek_result == 0) ? 0 : -1;
417 .
name =
"ogg_vorbis",
431 static int load_module(
void)
434 if (ast_format_def_register(&vorbis_f))
439 static int unload_module(
void)
444 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"OGG/Vorbis audio",
445 .support_level = AST_MODULE_SUPPORT_CORE,
447 .unload = unload_module,
Asterisk main include file. File version handling, generic pbx functions.
int eos
Indicates whether an End of Stream condition has been detected.
I/O Management (derived from Cheops-NG)
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
off_t writing_pcm_pos
Stores the current pcm position to support tell() on writing mode.
struct ast_frame fr
frame produced by read, typically
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
union ast_frame::@224 data
Module has failed to load, may be in an inconsistent state.
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Data structure associated with a single frame of data.
int writing
Indicates whether this filestream is set up for reading or writing.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.