2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2005, Jeff Ollie
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
19 * \brief OGG/Vorbis streams.
20 * \arg File name extension: ogg
24 /* the order of these dependencies is important... it also specifies
25 the link order of the libraries during linking
29 <depend>vorbis</depend>
35 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
37 #include <sys/types.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
47 #include <vorbis/codec.h>
48 #include <vorbis/vorbisenc.h>
55 #include "asterisk/lock.h"
56 #include "asterisk/channel.h"
57 #include "asterisk/file.h"
58 #include "asterisk/logger.h"
59 #include "asterisk/module.h"
62 * this is the number of samples we deal with. Samples are converted
63 * to SLINEAR so each one uses 2 bytes in the buffer.
65 #define SAMPLES_MAX 160
66 #define BUF_SIZE (2*SAMPLES_MAX)
68 #define BLOCK_SIZE 4096 /* used internally in the vorbis routines */
70 struct vorbis_desc
{ /* format specific parameters */
71 /* structures for handling the Ogg container */
77 /* structures for handling Vorbis audio data */
83 /*! \brief Indicates whether this filestream is set up for reading or writing. */
86 /*! \brief Indicates whether an End of Stream condition has been detected. */
91 * \brief Create a new OGG/Vorbis filestream and set it up for reading.
92 * \param s File that points to on disk storage of the OGG/Vorbis data.
93 * \return The new filestream.
95 static int ogg_vorbis_open(struct ast_filestream
*s
)
102 struct vorbis_desc
*tmp
= (struct vorbis_desc
*)s
->_private
;
106 ogg_sync_init(&tmp
->oy
);
108 buffer
= ogg_sync_buffer(&tmp
->oy
, BLOCK_SIZE
);
109 bytes
= fread(buffer
, 1, BLOCK_SIZE
, s
->f
);
110 ogg_sync_wrote(&tmp
->oy
, bytes
);
112 result
= ogg_sync_pageout(&tmp
->oy
, &tmp
->og
);
114 if(bytes
< BLOCK_SIZE
) {
115 ast_log(LOG_ERROR
, "Run out of data...\n");
117 ast_log(LOG_ERROR
, "Input does not appear to be an Ogg bitstream.\n");
119 ogg_sync_clear(&tmp
->oy
);
123 ogg_stream_init(&tmp
->os
, ogg_page_serialno(&tmp
->og
));
124 vorbis_info_init(&tmp
->vi
);
125 vorbis_comment_init(&tmp
->vc
);
127 if (ogg_stream_pagein(&tmp
->os
, &tmp
->og
) < 0) {
128 ast_log(LOG_ERROR
, "Error reading first page of Ogg bitstream data.\n");
130 ogg_stream_clear(&tmp
->os
);
131 vorbis_comment_clear(&tmp
->vc
);
132 vorbis_info_clear(&tmp
->vi
);
133 ogg_sync_clear(&tmp
->oy
);
137 if (ogg_stream_packetout(&tmp
->os
, &tmp
->op
) != 1) {
138 ast_log(LOG_ERROR
, "Error reading initial header packet.\n");
142 if (vorbis_synthesis_headerin(&tmp
->vi
, &tmp
->vc
, &tmp
->op
) < 0) {
143 ast_log(LOG_ERROR
, "This Ogg bitstream does not contain Vorbis audio data.\n");
147 for (i
= 0; i
< 2 ; ) {
149 result
= ogg_sync_pageout(&tmp
->oy
, &tmp
->og
);
153 ogg_stream_pagein(&tmp
->os
, &tmp
->og
);
155 result
= ogg_stream_packetout(&tmp
->os
,&tmp
->op
);
159 ast_log(LOG_ERROR
, "Corrupt secondary header. Exiting.\n");
162 vorbis_synthesis_headerin(&tmp
->vi
, &tmp
->vc
, &tmp
->op
);
168 buffer
= ogg_sync_buffer(&tmp
->oy
, BLOCK_SIZE
);
169 bytes
= fread(buffer
, 1, BLOCK_SIZE
, s
->f
);
170 if (bytes
== 0 && i
< 2) {
171 ast_log(LOG_ERROR
, "End of file before finding all Vorbis headers!\n");
174 ogg_sync_wrote(&tmp
->oy
, bytes
);
177 for (ptr
= tmp
->vc
.user_comments
; *ptr
; ptr
++)
178 ast_log(LOG_DEBUG
, "OGG/Vorbis comment: %s\n", *ptr
);
179 ast_log(LOG_DEBUG
, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp
->vi
.channels
, tmp
->vi
.rate
);
180 ast_log(LOG_DEBUG
, "OGG/Vorbis file encoded by: %s\n", tmp
->vc
.vendor
);
182 if (tmp
->vi
.channels
!= 1) {
183 ast_log(LOG_ERROR
, "Only monophonic OGG/Vorbis files are currently supported!\n");
187 if (tmp
->vi
.rate
!= DEFAULT_SAMPLE_RATE
) {
188 ast_log(LOG_ERROR
, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
189 vorbis_block_clear(&tmp
->vb
);
190 vorbis_dsp_clear(&tmp
->vd
);
194 vorbis_synthesis_init(&tmp
->vd
, &tmp
->vi
);
195 vorbis_block_init(&tmp
->vd
, &tmp
->vb
);
201 * \brief Create a new OGG/Vorbis filestream and set it up for writing.
202 * \param s File pointer that points to on-disk storage.
203 * \param comment Comment that should be embedded in the OGG/Vorbis file.
204 * \return A new filestream.
206 static int ogg_vorbis_rewrite(struct ast_filestream
*s
,
210 ogg_packet header_comm
;
211 ogg_packet header_code
;
212 struct vorbis_desc
*tmp
= (struct vorbis_desc
*)s
->_private
;
216 vorbis_info_init(&tmp
->vi
);
218 if (vorbis_encode_init_vbr(&tmp
->vi
, 1, DEFAULT_SAMPLE_RATE
, 0.4)) {
219 ast_log(LOG_ERROR
, "Unable to initialize Vorbis encoder!\n");
223 vorbis_comment_init(&tmp
->vc
);
224 vorbis_comment_add_tag(&tmp
->vc
, "ENCODER", "Asterisk PBX");
226 vorbis_comment_add_tag(&tmp
->vc
, "COMMENT", (char *) comment
);
228 vorbis_analysis_init(&tmp
->vd
, &tmp
->vi
);
229 vorbis_block_init(&tmp
->vd
, &tmp
->vb
);
231 ogg_stream_init(&tmp
->os
, ast_random());
233 vorbis_analysis_headerout(&tmp
->vd
, &tmp
->vc
, &header
, &header_comm
,
235 ogg_stream_packetin(&tmp
->os
, &header
);
236 ogg_stream_packetin(&tmp
->os
, &header_comm
);
237 ogg_stream_packetin(&tmp
->os
, &header_code
);
240 if (ogg_stream_flush(&tmp
->os
, &tmp
->og
) == 0)
242 fwrite(tmp
->og
.header
, 1, tmp
->og
.header_len
, s
->f
);
243 fwrite(tmp
->og
.body
, 1, tmp
->og
.body_len
, s
->f
);
244 if (ogg_page_eos(&tmp
->og
))
252 * \brief Write out any pending encoded data.
253 * \param s An OGG/Vorbis filestream.
254 * \param f The file to write to.
256 static void write_stream(struct vorbis_desc
*s
, FILE *f
)
258 while (vorbis_analysis_blockout(&s
->vd
, &s
->vb
) == 1) {
259 vorbis_analysis(&s
->vb
, NULL
);
260 vorbis_bitrate_addblock(&s
->vb
);
262 while (vorbis_bitrate_flushpacket(&s
->vd
, &s
->op
)) {
263 ogg_stream_packetin(&s
->os
, &s
->op
);
265 if (ogg_stream_pageout(&s
->os
, &s
->og
) == 0) {
268 fwrite(s
->og
.header
, 1, s
->og
.header_len
, f
);
269 fwrite(s
->og
.body
, 1, s
->og
.body_len
, f
);
270 if (ogg_page_eos(&s
->og
)) {
279 * \brief Write audio data from a frame to an OGG/Vorbis filestream.
280 * \param fs An OGG/Vorbis filestream.
281 * \param f A frame containing audio to be written to the filestream.
282 * \return -1 if there was an error, 0 on success.
284 static int ogg_vorbis_write(struct ast_filestream
*fs
, struct ast_frame
*f
)
289 struct vorbis_desc
*s
= (struct vorbis_desc
*)fs
->_private
;
292 ast_log(LOG_ERROR
, "This stream is not set up for writing!\n");
296 if (f
->frametype
!= AST_FRAME_VOICE
) {
297 ast_log(LOG_WARNING
, "Asked to write non-voice frame!\n");
300 if (f
->subclass
!= AST_FORMAT_SLINEAR
) {
301 ast_log(LOG_WARNING
, "Asked to write non-SLINEAR frame (%d)!\n",
308 data
= (short *) f
->data
;
310 buffer
= vorbis_analysis_buffer(&s
->vd
, f
->samples
);
312 for (i
= 0; i
< f
->samples
; i
++)
313 buffer
[0][i
] = (double)data
[i
] / 32768.0;
315 vorbis_analysis_wrote(&s
->vd
, f
->samples
);
317 write_stream(s
, fs
->f
);
323 * \brief Close a OGG/Vorbis filestream.
324 * \param fs A OGG/Vorbis filestream.
326 static void ogg_vorbis_close(struct ast_filestream
*fs
)
328 struct vorbis_desc
*s
= (struct vorbis_desc
*)fs
->_private
;
331 /* Tell the Vorbis encoder that the stream is finished
332 * and write out the rest of the data */
333 vorbis_analysis_wrote(&s
->vd
, 0);
334 write_stream(s
, fs
->f
);
337 ogg_stream_clear(&s
->os
);
338 vorbis_block_clear(&s
->vb
);
339 vorbis_dsp_clear(&s
->vd
);
340 vorbis_comment_clear(&s
->vc
);
341 vorbis_info_clear(&s
->vi
);
344 ogg_sync_clear(&s
->oy
);
349 * \brief Get audio data.
350 * \param fs An OGG/Vorbis filestream.
351 * \param pcm Pointer to a buffere to store audio data in.
354 static int read_samples(struct ast_filestream
*fs
, float ***pcm
)
360 struct vorbis_desc
*s
= (struct vorbis_desc
*)fs
->_private
;
363 samples_in
= vorbis_synthesis_pcmout(&s
->vd
, pcm
);
364 if (samples_in
> 0) {
368 /* The Vorbis decoder needs more data... */
369 /* See ifOGG has any packets in the current page for the Vorbis decoder. */
370 result
= ogg_stream_packetout(&s
->os
, &s
->op
);
372 /* Yes OGG had some more packets for the Vorbis decoder. */
373 if (vorbis_synthesis(&s
->vb
, &s
->op
) == 0) {
374 vorbis_synthesis_blockin(&s
->vd
, &s
->vb
);
382 "Corrupt or missing data at this page position; continuing...\n");
384 /* No more packets left in the current page... */
387 /* No more pages left in the stream */
392 /* See ifOGG has any pages in it's internal buffers */
393 result
= ogg_sync_pageout(&s
->oy
, &s
->og
);
395 /* Yes, OGG has more pages in it's internal buffers,
396 add the page to the stream state */
397 result
= ogg_stream_pagein(&s
->os
, &s
->og
);
399 /* Yes, got a new,valid page */
400 if (ogg_page_eos(&s
->og
)) {
406 "Invalid page in the bitstream; continuing...\n");
411 "Corrupt or missing data in bitstream; continuing...\n");
413 /* No, we need to read more data from the file descrptor */
414 /* get a buffer from OGG to read the data into */
415 buffer
= ogg_sync_buffer(&s
->oy
, BLOCK_SIZE
);
416 /* read more data from the file descriptor */
417 bytes
= fread(buffer
, 1, BLOCK_SIZE
, fs
->f
);
418 /* Tell OGG how many bytes we actually read into the buffer */
419 ogg_sync_wrote(&s
->oy
, bytes
);
428 * \brief Read a frame full of audio data from the filestream.
429 * \param fs The filestream.
430 * \param whennext Number of sample times to schedule the next call.
431 * \return A pointer to a frame containing audio data or NULL ifthere is no more audio data.
433 static struct ast_frame
*ogg_vorbis_read(struct ast_filestream
*fs
,
439 double accumulator
[SAMPLES_MAX
];
443 struct vorbis_desc
*s
= (struct vorbis_desc
*)fs
->_private
;
444 short *buf
; /* SLIN data buffer */
446 fs
->fr
.frametype
= AST_FRAME_VOICE
;
447 fs
->fr
.subclass
= AST_FORMAT_SLINEAR
;
449 AST_FRAME_SET_BUFFER(&fs
->fr
, fs
->buf
, AST_FRIENDLY_OFFSET
, BUF_SIZE
);
450 buf
= (short *)(fs
->fr
.data
); /* SLIN data buffer */
452 while (samples_out
!= SAMPLES_MAX
) {
454 int len
= SAMPLES_MAX
- samples_out
;
456 /* See ifVorbis decoder has some audio data for us ... */
457 samples_in
= read_samples(fs
, &pcm
);
461 /* Got some audio data from Vorbis... */
462 /* Convert the float audio data to 16-bit signed linear */
465 if (samples_in
> len
)
467 for (j
= 0; j
< samples_in
; j
++)
468 accumulator
[j
] = 0.0;
470 for (i
= 0; i
< s
->vi
.channels
; i
++) {
471 float *mono
= pcm
[i
];
472 for (j
= 0; j
< samples_in
; j
++)
473 accumulator
[j
] += mono
[j
];
476 for (j
= 0; j
< samples_in
; j
++) {
477 val
= accumulator
[j
] * 32767.0 / s
->vi
.channels
;
481 } else if (val
< -32768) {
485 buf
[samples_out
+ j
] = val
;
489 ast_log(LOG_WARNING
, "Clipping in frame %ld\n", (long) (s
->vd
.sequence
));
490 /* Tell the Vorbis decoder how many samples we actually used. */
491 vorbis_synthesis_read(&s
->vd
, samples_in
);
492 samples_out
+= samples_in
;
495 if (samples_out
> 0) {
496 fs
->fr
.datalen
= samples_out
* 2;
497 fs
->fr
.samples
= samples_out
;
498 *whennext
= samples_out
;
507 * \brief Trucate an OGG/Vorbis filestream.
508 * \param s The filestream to truncate.
509 * \return 0 on success, -1 on failure.
512 static int ogg_vorbis_trunc(struct ast_filestream
*s
)
514 ast_log(LOG_WARNING
, "Truncation is not supported on OGG/Vorbis streams!\n");
519 * \brief Seek to a specific position in an OGG/Vorbis filestream.
520 * \param s The filestream to truncate.
521 * \param sample_offset New position for the filestream, measured in 8KHz samples.
522 * \param whence Location to measure
523 * \return 0 on success, -1 on failure.
525 static int ogg_vorbis_seek(struct ast_filestream
*s
, off_t sample_offset
, int whence
)
527 ast_log(LOG_WARNING
, "Seeking is not supported on OGG/Vorbis streams!\n");
531 static off_t
ogg_vorbis_tell(struct ast_filestream
*s
)
533 ast_log(LOG_WARNING
, "Telling is not supported on OGG/Vorbis streams!\n");
537 static const struct ast_format vorbis_f
= {
538 .name
= "ogg_vorbis",
540 .format
= AST_FORMAT_SLINEAR
,
541 .open
= ogg_vorbis_open
,
542 .rewrite
= ogg_vorbis_rewrite
,
543 .write
= ogg_vorbis_write
,
544 .seek
= ogg_vorbis_seek
,
545 .trunc
= ogg_vorbis_trunc
,
546 .tell
= ogg_vorbis_tell
,
547 .read
= ogg_vorbis_read
,
548 .close
= ogg_vorbis_close
,
549 .buf_size
= BUF_SIZE
+ AST_FRIENDLY_OFFSET
,
550 .desc_size
= sizeof(struct vorbis_desc
),
553 static int load_module(void)
555 return ast_format_register(&vorbis_f
);
558 static int unload_module(void)
560 return ast_format_unregister(vorbis_f
.name
);
563 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "OGG/Vorbis audio");