Fri Aug 24 02:25:54 2007

Asterisk developer's documentation


format_ogg_vorbis.c File Reference

OGG/Vorbis streams. More...

#include "asterisk.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisenc.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"

Include dependency graph for format_ogg_vorbis.c:

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

 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"OGG/Vorbis audio")
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_frameogg_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_format vorbis_f


Detailed Description

OGG/Vorbis streams.

Definition in file format_ogg_vorbis.c.


Define Documentation

#define BLOCK_SIZE   4096

Definition at line 68 of file format_ogg_vorbis.c.

Referenced by ogg_vorbis_open(), and read_samples().

#define BUF_SIZE   (2*SAMPLES_MAX)

Definition at line 66 of file format_ogg_vorbis.c.

#define SAMPLES_MAX   160

Definition at line 65 of file format_ogg_vorbis.c.

Referenced by ogg_vorbis_read().


Function Documentation

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"OGG/Vorbis audio"   
)

static int load_module ( void   )  [static]

Definition at line 553 of file format_ogg_vorbis.c.

References ast_format_register, and vorbis_f.

00554 {
00555    return ast_format_register(&vorbis_f);
00556 }

static void ogg_vorbis_close ( struct ast_filestream fs  )  [static]

Close a OGG/Vorbis filestream.

Parameters:
fs A OGG/Vorbis filestream.

Definition at line 326 of file format_ogg_vorbis.c.

References ast_filestream::f, ast_filestream::private, s, and write_stream().

00327 {
00328    struct vorbis_desc *s = (struct vorbis_desc *)fs->private;
00329 
00330    if (s->writing) {
00331       /* Tell the Vorbis encoder that the stream is finished
00332        * and write out the rest of the data */
00333       vorbis_analysis_wrote(&s->vd, 0);
00334       write_stream(s, fs->f);
00335    }
00336 
00337    ogg_stream_clear(&s->os);
00338    vorbis_block_clear(&s->vb);
00339    vorbis_dsp_clear(&s->vd);
00340    vorbis_comment_clear(&s->vc);
00341    vorbis_info_clear(&s->vi);
00342 
00343    if (s->writing) {
00344       ogg_sync_clear(&s->oy);
00345    }
00346 }

static int ogg_vorbis_open ( struct ast_filestream s  )  [static]

Create a new OGG/Vorbis filestream and set it up for reading.

Parameters:
s File that points to on disk storage of the OGG/Vorbis data.
Returns:
The new filestream.

Definition at line 95 of file format_ogg_vorbis.c.

References ast_log(), BLOCK_SIZE, error(), LOG_ERROR, vorbis_desc::og, vorbis_desc::op, vorbis_desc::os, vorbis_desc::oy, result, s, vorbis_desc::vc, vorbis_desc::vi, and vorbis_desc::writing.

00096 {
00097    int i;
00098    int bytes;
00099    int result;
00100    char **ptr;
00101    char *buffer;
00102    struct vorbis_desc *tmp = (struct vorbis_desc *)s->private;
00103 
00104    tmp->writing = 0;
00105 
00106    ogg_sync_init(&tmp->oy);
00107 
00108    buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
00109    bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
00110    ogg_sync_wrote(&tmp->oy, bytes);
00111 
00112    result = ogg_sync_pageout(&tmp->oy, &tmp->og);
00113    if (result != 1) {
00114       if(bytes < BLOCK_SIZE) {
00115          ast_log(LOG_ERROR, "Run out of data...\n");
00116       } else {
00117          ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
00118       }
00119       ogg_sync_clear(&tmp->oy);
00120       return -1;
00121    }
00122    
00123    ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
00124    vorbis_info_init(&tmp->vi);
00125    vorbis_comment_init(&tmp->vc);
00126 
00127    if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { 
00128       ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
00129 error:
00130       ogg_stream_clear(&tmp->os);
00131       vorbis_comment_clear(&tmp->vc);
00132       vorbis_info_clear(&tmp->vi);
00133       ogg_sync_clear(&tmp->oy);
00134       return -1;
00135    }
00136    
00137    if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { 
00138       ast_log(LOG_ERROR, "Error reading initial header packet.\n");
00139       goto error;
00140    }
00141    
00142    if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { 
00143       ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
00144       goto error;
00145    }
00146    
00147    for (i = 0; i < 2 ; ) {
00148       while (i < 2) {
00149          result = ogg_sync_pageout(&tmp->oy, &tmp->og);
00150          if (result == 0)
00151             break;
00152          if (result == 1) {
00153             ogg_stream_pagein(&tmp->os, &tmp->og);
00154             while(i < 2) {
00155                result = ogg_stream_packetout(&tmp->os,&tmp->op);
00156                if(result == 0)
00157                   break;
00158                if(result < 0) {
00159                   ast_log(LOG_ERROR, "Corrupt secondary header.  Exiting.\n");
00160                   goto error;
00161                }
00162                vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
00163                i++;
00164             }
00165          }
00166       }
00167 
00168       buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
00169       bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
00170       if (bytes == 0 && i < 2) {
00171          ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
00172          goto error;
00173       }
00174       ogg_sync_wrote(&tmp->oy, bytes);
00175    }
00176    
00177    for (ptr = tmp->vc.user_comments; *ptr; ptr++)
00178       ast_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr);
00179    ast_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate);
00180    ast_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor);
00181 
00182    if (tmp->vi.channels != 1) {
00183       ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
00184       goto error;
00185    }
00186    
00187    if (tmp->vi.rate != DEFAULT_SAMPLE_RATE) {
00188       ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
00189       vorbis_block_clear(&tmp->vb);
00190       vorbis_dsp_clear(&tmp->vd);
00191       goto error;
00192    }
00193    
00194    vorbis_synthesis_init(&tmp->vd, &tmp->vi);
00195    vorbis_block_init(&tmp->vd, &tmp->vb);
00196 
00197    return 0;
00198 }

static struct ast_frame* ogg_vorbis_read ( struct ast_filestream fs,
int *  whennext 
) [static]

Read a frame full of audio data from the filestream.

Parameters:
fs The filestream.
whennext Number of sample times to schedule the next call.
Returns:
A pointer to a frame containing audio data or NULL ifthere is no more audio data.

Definition at line 433 of file format_ogg_vorbis.c.

References 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, ast_filestream::fr, ast_frame::frametype, len, LOG_WARNING, ast_frame::mallocd, ast_filestream::private, read_samples(), s, ast_frame::samples, SAMPLES_MAX, and ast_frame::subclass.

00435 {
00436    int clipflag = 0;
00437    int i;
00438    int j;
00439    double accumulator[SAMPLES_MAX];
00440    int val;
00441    int samples_in;
00442    int samples_out = 0;
00443    struct vorbis_desc *s = (struct vorbis_desc *)fs->private;
00444    short *buf; /* SLIN data buffer */
00445 
00446    fs->fr.frametype = AST_FRAME_VOICE;
00447    fs->fr.subclass = AST_FORMAT_SLINEAR;
00448    fs->fr.mallocd = 0;
00449    AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
00450    buf = (short *)(fs->fr.data); /* SLIN data buffer */
00451 
00452    while (samples_out != SAMPLES_MAX) {
00453       float **pcm;
00454       int len = SAMPLES_MAX - samples_out;
00455 
00456       /* See ifVorbis decoder has some audio data for us ... */
00457       samples_in = read_samples(fs, &pcm);
00458       if (samples_in <= 0)
00459          break;
00460 
00461       /* Got some audio data from Vorbis... */
00462       /* Convert the float audio data to 16-bit signed linear */
00463 
00464       clipflag = 0;
00465       if (samples_in > len)
00466          samples_in = len;
00467       for (j = 0; j < samples_in; j++)
00468          accumulator[j] = 0.0;
00469 
00470       for (i = 0; i < s->vi.channels; i++) {
00471          float *mono = pcm[i];
00472          for (j = 0; j < samples_in; j++)
00473             accumulator[j] += mono[j];
00474       }
00475 
00476       for (j = 0; j < samples_in; j++) {
00477          val = accumulator[j] * 32767.0 / s->vi.channels;
00478          if (val > 32767) {
00479             val = 32767;
00480             clipflag = 1;
00481          } else if (val < -32768) {
00482             val = -32768;
00483             clipflag = 1;
00484          }
00485          buf[samples_out + j] = val;
00486       }
00487 
00488       if (clipflag)
00489          ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long) (s->vd.sequence));
00490       /* Tell the Vorbis decoder how many samples we actually used. */
00491       vorbis_synthesis_read(&s->vd, samples_in);
00492       samples_out += samples_in;
00493    }
00494 
00495    if (samples_out > 0) {
00496       fs->fr.datalen = samples_out * 2;
00497       fs->fr.samples = samples_out;
00498       *whennext = samples_out;
00499 
00500       return &fs->fr;
00501    } else {
00502       return NULL;
00503    }
00504 }

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.

Parameters:
s File pointer that points to on-disk storage.
comment Comment that should be embedded in the OGG/Vorbis file.
Returns:
A new filestream.

Definition at line 206 of file format_ogg_vorbis.c.

References ast_log(), ast_random(), DEFAULT_SAMPLE_RATE, vorbis_desc::eos, LOG_ERROR, vorbis_desc::og, vorbis_desc::os, s, vorbis_desc::vb, vorbis_desc::vc, vorbis_desc::vd, vorbis_desc::vi, and vorbis_desc::writing.

00208 {
00209    ogg_packet header;
00210    ogg_packet header_comm;
00211    ogg_packet header_code;
00212    struct vorbis_desc *tmp = (struct vorbis_desc *)s->private;
00213 
00214    tmp->writing = 1;
00215 
00216    vorbis_info_init(&tmp->vi);
00217 
00218    if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) {
00219       ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n");
00220       return -1;
00221    }
00222 
00223    vorbis_comment_init(&tmp->vc);
00224    vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX");
00225    if (comment)
00226       vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment);
00227 
00228    vorbis_analysis_init(&tmp->vd, &tmp->vi);
00229    vorbis_block_init(&tmp->vd, &tmp->vb);
00230 
00231    ogg_stream_init(&tmp->os, ast_random());
00232 
00233    vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm,
00234               &header_code);
00235    ogg_stream_packetin(&tmp->os, &header);
00236    ogg_stream_packetin(&tmp->os, &header_comm);
00237    ogg_stream_packetin(&tmp->os, &header_code);
00238 
00239    while (!tmp->eos) {
00240       if (ogg_stream_flush(&tmp->os, &tmp->og) == 0)
00241          break;
00242       fwrite(tmp->og.header, 1, tmp->og.header_len, s->f);
00243       fwrite(tmp->og.body, 1, tmp->og.body_len, s->f);
00244       if (ogg_page_eos(&tmp->og))
00245          tmp->eos = 1;
00246    }
00247 
00248    return 0;
00249 }

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.

Parameters:
s The filestream to truncate.
sample_offset New position for the filestream, measured in 8KHz samples.
whence Location to measure
Returns:
0 on success, -1 on failure.

Definition at line 525 of file format_ogg_vorbis.c.

References ast_log(), and LOG_WARNING.

00526 {
00527    ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n");
00528    return -1;
00529 }

static off_t ogg_vorbis_tell ( struct ast_filestream s  )  [static]

Definition at line 531 of file format_ogg_vorbis.c.

References ast_log(), and LOG_WARNING.

00532 {
00533    ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n");
00534    return -1;
00535 }

static int ogg_vorbis_trunc ( struct ast_filestream s  )  [static]

Trucate an OGG/Vorbis filestream.

Parameters:
s The filestream to truncate.
Returns:
0 on success, -1 on failure.

Definition at line 512 of file format_ogg_vorbis.c.

References ast_log(), and LOG_WARNING.

00513 {
00514    ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n");
00515    return -1;
00516 }

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.

Parameters:
fs An OGG/Vorbis filestream.
f A frame containing audio to be written to the filestream.
Returns:
-1 if there was an error, 0 on success.

Definition at line 284 of file format_ogg_vorbis.c.

References AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_filestream::f, f, LOG_ERROR, LOG_WARNING, ast_filestream::private, s, and write_stream().

00285 {
00286    int i;
00287    float **buffer;
00288    short *data;
00289    struct vorbis_desc *s = (struct vorbis_desc *)fs->private;
00290 
00291    if (!s->writing) {
00292       ast_log(LOG_ERROR, "This stream is not set up for writing!\n");
00293       return -1;
00294    }
00295 
00296    if (f->frametype != AST_FRAME_VOICE) {
00297       ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00298       return -1;
00299    }
00300    if (f->subclass != AST_FORMAT_SLINEAR) {
00301       ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%d)!\n",
00302             f->subclass);
00303       return -1;
00304    }
00305    if (!f->datalen)
00306       return -1;
00307 
00308    data = (short *) f->data;
00309 
00310    buffer = vorbis_analysis_buffer(&s->vd, f->samples);
00311 
00312    for (i = 0; i < f->samples; i++)
00313       buffer[0][i] = (double)data[i] / 32768.0;
00314 
00315    vorbis_analysis_wrote(&s->vd, f->samples);
00316 
00317    write_stream(s, fs->f);
00318 
00319    return 0;
00320 }

static int read_samples ( struct ast_filestream fs,
float ***  pcm 
) [static]

Get audio data.

Parameters:
fs An OGG/Vorbis filestream.
pcm Pointer to a buffere to store audio data in.

Definition at line 354 of file format_ogg_vorbis.c.

References ast_log(), BLOCK_SIZE, ast_filestream::f, LOG_WARNING, ast_filestream::private, result, and s.

Referenced by ogg_vorbis_read().

00355 {
00356    int samples_in;
00357    int result;
00358    char *buffer;
00359    int bytes;
00360    struct vorbis_desc *s = (struct vorbis_desc *)fs->private;
00361 
00362    while (1) {
00363       samples_in = vorbis_synthesis_pcmout(&s->vd, pcm);
00364       if (samples_in > 0) {
00365          return samples_in;
00366       }
00367 
00368       /* The Vorbis decoder needs more data... */
00369       /* See ifOGG has any packets in the current page for the Vorbis decoder. */
00370       result = ogg_stream_packetout(&s->os, &s->op);
00371       if (result > 0) {
00372          /* Yes OGG had some more packets for the Vorbis decoder. */
00373          if (vorbis_synthesis(&s->vb, &s->op) == 0) {
00374             vorbis_synthesis_blockin(&s->vd, &s->vb);
00375          }
00376 
00377          continue;
00378       }
00379 
00380       if (result < 0)
00381          ast_log(LOG_WARNING,
00382                "Corrupt or missing data at this page position; continuing...\n");
00383 
00384       /* No more packets left in the current page... */
00385 
00386       if (s->eos) {
00387          /* No more pages left in the stream */
00388          return -1;
00389       }
00390 
00391       while (!s->eos) {
00392          /* See ifOGG has any pages in it's internal buffers */
00393          result = ogg_sync_pageout(&s->oy, &s->og);
00394          if (result > 0) {
00395             /* Yes, OGG has more pages in it's internal buffers,
00396                add the page to the stream state */
00397             result = ogg_stream_pagein(&s->os, &s->og);
00398             if (result == 0) {
00399                /* Yes, got a new,valid page */
00400                if (ogg_page_eos(&s->og)) {
00401                   s->eos = 1;
00402                }
00403                break;
00404             }
00405             ast_log(LOG_WARNING,
00406                   "Invalid page in the bitstream; continuing...\n");
00407          }
00408 
00409          if (result < 0)
00410             ast_log(LOG_WARNING,
00411                   "Corrupt or missing data in bitstream; continuing...\n");
00412 
00413          /* No, we need to read more data from the file descrptor */
00414          /* get a buffer from OGG to read the data into */
00415          buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
00416          /* read more data from the file descriptor */
00417          bytes = fread(buffer, 1, BLOCK_SIZE, fs->f);
00418          /* Tell OGG how many bytes we actually read into the buffer */
00419          ogg_sync_wrote(&s->oy, bytes);
00420          if (bytes == 0) {
00421             s->eos = 1;
00422          }
00423       }
00424    }
00425 }

static int unload_module ( void   )  [static]

Definition at line 558 of file format_ogg_vorbis.c.

References ast_format_unregister(), ast_format::name, and vorbis_f.

00559 {
00560    return ast_format_unregister(vorbis_f.name);
00561 }

static void write_stream ( struct vorbis_desc s,
FILE *  f 
) [static]

Write out any pending encoded data.

Parameters:
s An OGG/Vorbis filestream.
f The file to write to.

Definition at line 256 of file format_ogg_vorbis.c.

References s.

Referenced by ogg_vorbis_close(), and ogg_vorbis_write().

00257 {
00258    while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
00259       vorbis_analysis(&s->vb, NULL);
00260       vorbis_bitrate_addblock(&s->vb);
00261 
00262       while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) {
00263          ogg_stream_packetin(&s->os, &s->op);
00264          while (!s->eos) {
00265             if (ogg_stream_pageout(&s->os, &s->og) == 0) {
00266                break;
00267             }
00268             fwrite(s->og.header, 1, s->og.header_len, f);
00269             fwrite(s->og.body, 1, s->og.body_len, f);
00270             if (ogg_page_eos(&s->og)) {
00271                s->eos = 1;
00272             }
00273          }
00274       }
00275    }
00276 }


Variable Documentation

struct ast_format vorbis_f [static]

Definition at line 537 of file format_ogg_vorbis.c.

Referenced by load_module(), and unload_module().


Generated on Fri Aug 24 02:25:54 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1