Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:54 2009

## Asterisk developer's documentation

# format_ogg_vorbis.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 2005, Jeff Ollie
    00005  *
    00006  * See http://www.asterisk.org for more information about
    00007  * the Asterisk project. Please do not directly contact
    00008  * any of the maintainers of this project for assistance;
    00009  * the project provides a web site, mailing lists and IRC
    00010  * channels for your use.
    00011  *
    00012  * This program is free software, distributed under the terms of
    00013  * the GNU General Public License Version 2. See the LICENSE file
    00014  * at the top of the source tree.
    00015  */
    00016
    00017 /*! \file
    00018  *
    00019  * \brief OGG/Vorbis streams.
    00020  * \arg File name extension: ogg
    00021  * \ingroup formats
    00022  */
    00023
    00024 #include <sys/types.h>
    00025 #include <netinet/in.h>
    00026 #include <arpa/inet.h>
    00027 #include <stdlib.h>
    00028 #include <sys/time.h>
    00029 #include <stdio.h>
    00030 #include <unistd.h>
    00031 #include <errno.h>
    00032 #include <string.h>
    00033
    00034 #include <vorbis/codec.h>
    00035 #include <vorbis/vorbisenc.h>
    00036
    00037 #ifdef _WIN32
    00038 #include <io.h>
    00039 #include <fcntl.h>
    00040 #endif
    00041
    00042 #include "asterisk.h"
    00043
    00044 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
    00045
    00046 #include "asterisk/lock.h"
    00047 #include "asterisk/channel.h"
    00048 #include "asterisk/file.h"
    00049 #include "asterisk/logger.h"
    00050 #include "asterisk/module.h"
    00051
    00052 #define SAMPLES_MAX 160
    00053 #define BLOCK_SIZE 4096
    00054
    00055
    00056 struct ast_filestream {
    00057    void *reserved[AST_RESERVED_POINTERS];
    00058
    00059    FILE *f;
    00060
    00061    /* structures for handling the Ogg container */
    00062    ogg_sync_state  oy;
    00063    ogg_stream_state os;
    00064    ogg_page  og;
    00065    ogg_packet   op;
    00066
    00067    /* structures for handling Vorbis audio data */
    00068    vorbis_info  vi;
    00069    vorbis_comment  vc;
    00070    vorbis_dsp_state vd;
    00071    vorbis_block    vb;
    00072
    00073    /*! \brief Indicates whether this filestream is set up for reading or writing. */
    00074    int writing;
    00075
    00076    /*! \brief Indicates whether an End of Stream condition has been detected. */
    00077    int eos;
    00078
    00079    /*! \brief Buffer to hold audio data. */
    00080    short buffer[SAMPLES_MAX];
    00081
    00082    /*! \brief Asterisk frame object. */
    00083    struct ast_frame fr;
    00084    char waste[AST_FRIENDLY_OFFSET];
    00085    char empty;
    00086 };
    00087
    00088 AST_MUTEX_DEFINE_STATIC(ogg_vorbis_lock);
    00089 static int glistcnt = 0;
    00090
    00091 static char *name = "ogg_vorbis";
    00092 static char *desc = "OGG/Vorbis audio";
    00093 static char *exts = "ogg";
    00094
    00095 /*!
    00096  * \brief Create a new OGG/Vorbis filestream and set it up for reading.
    00097  * \param f File that points to on disk storage of the OGG/Vorbis data.
    00098  * \return The new filestream.
    00099  */
    00100 static struct ast_filestream *ogg_vorbis_open(FILE *f)
    00101 {
    00102    int i;
    00103    int bytes;
    00104    int result;
    00105    char **ptr;
    00106    char *buffer;
    00107
    00108    struct ast_filestream *tmp;
    00109
    00110    if((tmp = malloc(sizeof(struct ast_filestream)))) {
    00111       memset(tmp, 0, sizeof(struct ast_filestream));
    00112
    00113       tmp->writing = 0;
    00114       tmp->f = f;
    00115
    00116       ogg_sync_init(&tmp->oy);
    00117
    00118       buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
    00119       bytes = fread(buffer, 1, BLOCK_SIZE, f);
    00120       ogg_sync_wrote(&tmp->oy, bytes);
    00121
    00122       result = ogg_sync_pageout(&tmp->oy, &tmp->og);
    00123       if(result != 1) {
    00124          if(bytes < BLOCK_SIZE) {
    00125             ast_log(LOG_ERROR, "Run out of data...\n");
    00126          } else {
    00127             ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
    00128          }
    00129          fclose(f);
    00130          ogg_sync_clear(&tmp->oy);
    00131          free(tmp);
    00132          return NULL;
    00133       }
    00134
    00135       ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
    00136       vorbis_info_init(&tmp->vi);
    00137       vorbis_comment_init(&tmp->vc);
    00138
    00139       if(ogg_stream_pagein(&tmp->os, &tmp->og) < 0) {
    00140          ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
    00141          fclose(f);
    00142          ogg_stream_clear(&tmp->os);
    00143          vorbis_comment_clear(&tmp->vc);
    00144          vorbis_info_clear(&tmp->vi);
    00145          ogg_sync_clear(&tmp->oy);
    00146          free(tmp);
    00147          return NULL;
    00148       }
    00149
    00150       if(ogg_stream_packetout(&tmp->os, &tmp->op) != 1) {
    00151          ast_log(LOG_ERROR, "Error reading initial header packet.\n");
    00152          fclose(f);
    00153          ogg_stream_clear(&tmp->os);
    00154          vorbis_comment_clear(&tmp->vc);
    00155          vorbis_info_clear(&tmp->vi);
    00156          ogg_sync_clear(&tmp->oy);
    00157          free(tmp);
    00158          return NULL;
    00159       }
    00160
    00161       if(vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) {
    00162          ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
    00163          fclose(f);
    00164          ogg_stream_clear(&tmp->os);
    00165          vorbis_comment_clear(&tmp->vc);
    00166          vorbis_info_clear(&tmp->vi);
    00167          ogg_sync_clear(&tmp->oy);
    00168          free(tmp);
    00169          return NULL;
    00170       }
    00171
    00172       i = 0;
    00173       while(i < 2) {
    00174          while(i < 2){
    00175             result = ogg_sync_pageout(&tmp->oy, &tmp->og);
    00176             if(result == 0)
    00177                break;
    00178             if(result == 1) {
    00179                ogg_stream_pagein(&tmp->os, &tmp->og);
    00180                while(i < 2) {
    00181                   result = ogg_stream_packetout(&tmp->os,&tmp->op);
    00182                   if(result == 0)
    00183                      break;
    00184                   if(result < 0) {
    00185                      ast_log(LOG_ERROR, "Corrupt secondary header.  Exiting.\n");
    00186                      fclose(f);
    00187                      ogg_stream_clear(&tmp->os);
    00188                      vorbis_comment_clear(&tmp->vc);
    00189                      vorbis_info_clear(&tmp->vi);
    00190                      ogg_sync_clear(&tmp->oy);
    00191                      free(tmp);
    00192                      return NULL;
    00193                   }
    00194                   vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
    00195                   i++;
    00196                }
    00197             }
    00198          }
    00199
    00200          buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
    00201          bytes = fread(buffer, 1, BLOCK_SIZE, f);
    00202          if(bytes == 0 && i < 2) {
    00203             ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
    00204             fclose(f);
    00205             ogg_stream_clear(&tmp->os);
    00206             vorbis_comment_clear(&tmp->vc);
    00207             vorbis_info_clear(&tmp->vi);
    00208             ogg_sync_clear(&tmp->oy);
    00209             free(tmp);
    00210             return NULL;
    00211          }
    00212          ogg_sync_wrote(&tmp->oy, bytes);
    00213       }
    00214
    00215       ptr = tmp->vc.user_comments;
    00216       while(*ptr){
    00217          ast_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr);
    00218          ++ptr;
    00219       }
    00220       ast_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate);
    00221       ast_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor);
    00222
    00223       if(tmp->vi.channels != 1) {
    00224          ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
    00225          ogg_stream_clear(&tmp->os);
    00226          vorbis_comment_clear(&tmp->vc);
    00227          vorbis_info_clear(&tmp->vi);
    00228          ogg_sync_clear(&tmp->oy);
    00229          free(tmp);
    00230          return NULL;
    00231       }
    00232
    00233
    00234       if(tmp->vi.rate != 8000) {
    00235          ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
    00236          fclose(f);
    00237          ogg_stream_clear(&tmp->os);
    00238          vorbis_block_clear(&tmp->vb);
    00239          vorbis_dsp_clear(&tmp->vd);
    00240          vorbis_comment_clear(&tmp->vc);
    00241          vorbis_info_clear(&tmp->vi);
    00242          ogg_sync_clear(&tmp->oy);
    00243          free(tmp);
    00244          return NULL;
    00245       }
    00246
    00247       vorbis_synthesis_init(&tmp->vd, &tmp->vi);
    00248       vorbis_block_init(&tmp->vd, &tmp->vb);
    00249
    00250       if(ast_mutex_lock(&ogg_vorbis_lock)) {
    00251          ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
    00252          fclose(f);
    00253          ogg_stream_clear(&tmp->os);
    00254          vorbis_block_clear(&tmp->vb);
    00255          vorbis_dsp_clear(&tmp->vd);
    00256          vorbis_comment_clear(&tmp->vc);
    00257          vorbis_info_clear(&tmp->vi);
    00258          ogg_sync_clear(&tmp->oy);
    00259          free(tmp);
    00260          return NULL;
    00261       }
    00262       glistcnt++;
    00263       ast_mutex_unlock(&ogg_vorbis_lock);
    00264       ast_update_use_count();
    00265    }
    00266    return tmp;
    00267 }
    00268
    00269 /*!
    00270  * \brief Create a new OGG/Vorbis filestream and set it up for writing.
    00271  * \param f File pointer that points to on-disk storage.
    00272  * \param comment Comment that should be embedded in the OGG/Vorbis file.
    00273  * \return A new filestream.
    00274  */
    00275 static struct ast_filestream *ogg_vorbis_rewrite(FILE *f, const char *comment)
    00276 {
    00277    ogg_packet header;
    00278    ogg_packet header_comm;
    00279    ogg_packet header_code;
    00280
    00281    struct ast_filestream *tmp;
    00282
    00283    if((tmp = malloc(sizeof(struct ast_filestream)))) {
    00284       memset(tmp, 0, sizeof(struct ast_filestream));
    00285
    00286       tmp->writing = 1;
    00287       tmp->f = f;
    00288
    00289       vorbis_info_init(&tmp->vi);
    00290
    00291       if(vorbis_encode_init_vbr(&tmp->vi, 1, 8000, 0.4)) {
    00292          ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n");
    00293          free(tmp);
    00294          return NULL;
    00295       }
    00296
    00297       vorbis_comment_init(&tmp->vc);
    00298       vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX");
    00299       if(comment)
    00300          vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment);
    00301
    00302       vorbis_analysis_init(&tmp->vd, &tmp->vi);
    00303       vorbis_block_init(&tmp->vd, &tmp->vb);
    00304
    00305       ogg_stream_init(&tmp->os, rand());
    00306
    00307       vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm, &header_code);
    00308       ogg_stream_packetin(&tmp->os, &header);
    00309       ogg_stream_packetin(&tmp->os, &header_comm);
    00310       ogg_stream_packetin(&tmp->os, &header_code);
    00311
    00312       while(!tmp->eos) {
    00313          if(ogg_stream_flush(&tmp->os, &tmp->og) == 0)
    00314             break;
    00315          fwrite(tmp->og.header, 1, tmp->og.header_len, tmp->f);
    00316          fwrite(tmp->og.body, 1, tmp->og.body_len, tmp->f);
    00317          if(ogg_page_eos(&tmp->og))
    00318             tmp->eos = 1;
    00319       }
    00320
    00321       if(ast_mutex_lock(&ogg_vorbis_lock)) {
    00322          ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
    00323          fclose(f);
    00324          ogg_stream_clear(&tmp->os);
    00325          vorbis_block_clear(&tmp->vb);
    00326          vorbis_dsp_clear(&tmp->vd);
    00327          vorbis_comment_clear(&tmp->vc);
    00328          vorbis_info_clear(&tmp->vi);
    00329          free(tmp);
    00330          return NULL;
    00331       }
    00332       glistcnt++;
    00333       ast_mutex_unlock(&ogg_vorbis_lock);
    00334       ast_update_use_count();
    00335    }
    00336    return tmp;
    00337 }
    00338
    00339 /*!
    00340  * \brief Write out any pending encoded data.
    00341  * \param s A OGG/Vorbis filestream.
    00342  */
    00343 static void write_stream(struct ast_filestream *s)
    00344 {
    00345    while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
    00346       vorbis_analysis(&s->vb, NULL);
    00347       vorbis_bitrate_addblock(&s->vb);
    00348
    00349       while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) {
    00350          ogg_stream_packetin(&s->os, &s->op);
    00351          while (!s->eos) {
    00352             if(ogg_stream_pageout(&s->os, &s->og) == 0) {
    00353                break;
    00354             }
    00355             fwrite(s->og.header, 1, s->og.header_len, s->f);
    00356             fwrite(s->og.body, 1, s->og.body_len, s->f);
    00357             if(ogg_page_eos(&s->og)) {
    00358                s->eos = 1;
    00359             }
    00360          }
    00361       }
    00362    }
    00363 }
    00364
    00365 /*!
    00366  * \brief Write audio data from a frame to an OGG/Vorbis filestream.
    00367  * \param s A OGG/Vorbis filestream.
    00368  * \param f An frame containing audio to be written to the filestream.
    00369  * \return -1 ifthere was an error, 0 on success.
    00370  */
    00371 static int ogg_vorbis_write(struct ast_filestream *s, struct ast_frame *f)
    00372 {
    00373    int i;
    00374    float **buffer;
    00375    short *data;
    00376
    00377    if(!s->writing) {
    00378       ast_log(LOG_ERROR, "This stream is not set up for writing!\n");
    00379       return -1;
    00380    }
    00381
    00382    if(f->frametype != AST_FRAME_VOICE) {
    00383       ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
    00384       return -1;
    00385    }
    00386    if(f->subclass != AST_FORMAT_SLINEAR) {
    00387       ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%d)!\n", f->subclass);
    00388       return -1;
    00389    }
    00390    if(!f->datalen)
    00391       return -1;
    00392
    00393    data = (short *) f->data;
    00394
    00395    buffer = vorbis_analysis_buffer(&s->vd, f->samples);
    00396
    00397    for (i = 0; i < f->samples; i++) {
    00398       buffer[0][i] = data[i]/32768.f;
    00399    }
    00400
    00401    vorbis_analysis_wrote(&s->vd, f->samples);
    00402
    00403    write_stream(s);
    00404
    00405    return 0;
    00406 }
    00407
    00408 /*!
    00409  * \brief Close a OGG/Vorbis filestream.
    00410  * \param s A OGG/Vorbis filestream.
    00411  */
    00412 static void ogg_vorbis_close(struct ast_filestream *s)
    00413 {
    00414    if(ast_mutex_lock(&ogg_vorbis_lock)) {
    00415       ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
    00416       return;
    00417    }
    00418    glistcnt--;
    00419    ast_mutex_unlock(&ogg_vorbis_lock);
    00420    ast_update_use_count();
    00421
    00422    if(s->writing) {
    00423       /* Tell the Vorbis encoder that the stream is finished
    00424        * and write out the rest of the data */
    00425       vorbis_analysis_wrote(&s->vd, 0);
    00426       write_stream(s);
    00427    }
    00428
    00429    ogg_stream_clear(&s->os);
    00430    vorbis_block_clear(&s->vb);
    00431    vorbis_dsp_clear(&s->vd);
    00432    vorbis_comment_clear(&s->vc);
    00433    vorbis_info_clear(&s->vi);
    00434
    00435    if(s->writing) {
    00436       ogg_sync_clear(&s->oy);
    00437    }
    00438
    00439    fclose(s->f);
    00440    free(s);
    00441 }
    00442
    00443 /*!
    00444  * \brief Get audio data.
    00445  * \param s An OGG/Vorbis filestream.
    00446  * \param pcm Pointer to a buffere to store audio data in.
    00447  */
    00448
    00449 static int read_samples(struct ast_filestream *s, float ***pcm)
    00450 {
    00451    int samples_in;
    00452    int result;
    00453    char *buffer;
    00454    int bytes;
    00455
    00456    while (1) {
    00457       samples_in = vorbis_synthesis_pcmout(&s->vd, pcm);
    00458       if(samples_in > 0) {
    00459          return samples_in;
    00460       }
    00461
    00462       /* The Vorbis decoder needs more data... */
    00463       /* See ifOGG has any packets in the current page for the Vorbis decoder. */
    00464       result = ogg_stream_packetout(&s->os, &s->op);
    00465       if(result > 0) {
    00466          /* Yes OGG had some more packets for the Vorbis decoder. */
    00467          if(vorbis_synthesis(&s->vb, &s->op) == 0) {
    00468             vorbis_synthesis_blockin(&s->vd, &s->vb);
    00469          }
    00470
    00471          continue;
    00472       }
    00473
    00474       if(result < 0)
    00475          ast_log(LOG_WARNING, "Corrupt or missing data at this page position; continuing...\n");
    00476
    00477       /* No more packets left in the current page... */
    00478
    00479       if(s->eos) {
    00480          /* No more pages left in the stream */
    00481          return -1;
    00482       }
    00483
    00484       while (!s->eos) {
    00485          /* See ifOGG has any pages in it's internal buffers */
    00486          result = ogg_sync_pageout(&s->oy, &s->og);
    00487          if(result > 0) {
    00488             /* Yes, OGG has more pages in it's internal buffers,
    00489                add the page to the stream state */
    00490             result = ogg_stream_pagein(&s->os, &s->og);
    00491             if(result == 0) {
    00492                /* Yes, got a new,valid page */
    00493                if(ogg_page_eos(&s->og)) {
    00494                   s->eos = 1;
    00495                }
    00496                break;
    00497             }
    00498             ast_log(LOG_WARNING, "Invalid page in the bitstream; continuing...\n");
    00499          }
    00500
    00501          if(result < 0)
    00502             ast_log(LOG_WARNING, "Corrupt or missing data in bitstream; continuing...\n");
    00503
    00504          /* No, we need to read more data from the file descrptor */
    00505          /* get a buffer from OGG to read the data into */
    00506          buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
    00507          /* read more data from the file descriptor */
    00508          bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
    00509          /* Tell OGG how many bytes we actually read into the buffer */
    00510          ogg_sync_wrote(&s->oy, bytes);
    00511          if(bytes == 0) {
    00512             s->eos = 1;
    00513          }
    00514       }
    00515    }
    00516 }
    00517
    00518 /*!
    00519  * \brief Read a frame full of audio data from the filestream.
    00520  * \param s The filestream.
    00521  * \param whennext Number of sample times to schedule the next call.
    00522  * \return A pointer to a frame containing audio data or NULL ifthere is no more audio data.
    00523  */
    00524 static struct ast_frame *ogg_vorbis_read(struct ast_filestream *s, int *whennext)
    00525 {
    00526    int clipflag = 0;
    00527    int i;
    00528    int j;
    00529    float **pcm;
    00530    float *mono;
    00531    double accumulator[SAMPLES_MAX];
    00532    int val;
    00533    int samples_in;
    00534    int samples_out = 0;
    00535
    00536    while (1) {
    00537       /* See ifwe have filled up an audio frame yet */
    00538       if(samples_out == SAMPLES_MAX)
    00539          break;
    00540
    00541       /* See ifVorbis decoder has some audio data for us ... */
    00542       samples_in = read_samples(s, &pcm);
    00543       if(samples_in <= 0)
    00544          break;
    00545
    00546       /* Got some audio data from Vorbis... */
    00547       /* Convert the float audio data to 16-bit signed linear */
    00548
    00549       clipflag = 0;
    00550
    00551       samples_in = samples_in < (SAMPLES_MAX - samples_out) ? samples_in : (SAMPLES_MAX - samples_out);
    00552
    00553       for(j = 0; j < samples_in; j++)
    00554          accumulator[j] = 0.0;
    00555
    00556       for(i = 0; i < s->vi.channels; i++) {
    00557          mono = pcm[i];
    00558          for (j = 0; j < samples_in; j++) {
    00559             accumulator[j] += mono[j];
    00560          }
    00561       }
    00562
    00563       for (j = 0; j < samples_in; j++) {
    00564          val =  accumulator[j] * 32767.0 / s->vi.channels;
    00565          if(val > 32767) {
    00566             val = 32767;
    00567             clipflag = 1;
    00568          }
    00569          if(val < -32768) {
    00570             val = -32768;
    00571             clipflag = 1;
    00572          }
    00573          s->buffer[samples_out + j] = val;
    00574       }
    00575
    00576       if(clipflag)
    00577          ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long)(s->vd.sequence));
    00578
    00579       /* Tell the Vorbis decoder how many samples we actually used. */
    00580       vorbis_synthesis_read(&s->vd, samples_in);
    00581       samples_out += samples_in;
    00582    }
    00583
    00584    if(samples_out > 0) {
    00585       s->fr.frametype = AST_FRAME_VOICE;
    00586       s->fr.subclass = AST_FORMAT_SLINEAR;
    00587       s->fr.offset = AST_FRIENDLY_OFFSET;
    00588       s->fr.datalen = samples_out * 2;
    00589       s->fr.data = s->buffer;
    00590       s->fr.src = name;
    00591       s->fr.mallocd = 0;
    00592       s->fr.samples = samples_out;
    00593       *whennext = samples_out;
    00594
    00595       return &s->fr;
    00596    } else {
    00597       return NULL;
    00598    }
    00599 }
    00600
    00601 /*!
    00602  * \brief Trucate an OGG/Vorbis filestream.
    00603  * \param s The filestream to truncate.
    00604  * \return 0 on success, -1 on failure.
    00605  */
    00606
    00607 static int ogg_vorbis_trunc(struct ast_filestream *s)
    00608 {
    00609    ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n");
    00610    return -1;
    00611 }
    00612
    00613 /*!
    00614  * \brief Seek to a specific position in an OGG/Vorbis filestream.
    00615  * \param s The filestream to truncate.
    00616  * \param sample_offset New position for the filestream, measured in 8KHz samples.
    00617  * \param whence Location to measure
    00618  * \return 0 on success, -1 on failure.
    00619  */
    00620
    00621 static int ogg_vorbis_seek(struct ast_filestream *s, long sample_offset, int whence) {
    00622    ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n");
    00623    return -1;
    00624 }
    00625
    00626 static long ogg_vorbis_tell(struct ast_filestream *s) {
    00627    ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n");
    00628    return -1;
    00629 }
    00630
    00631 static char *ogg_vorbis_getcomment(struct ast_filestream *s) {
    00632    ast_log(LOG_WARNING, "Getting comments is not supported on OGG/Vorbis streams!\n");
    00633    return NULL;
    00634 }
    00635
    00636 int load_module()
    00637 {
    00638    return ast_format_register(name, exts, AST_FORMAT_SLINEAR,
    00639                ogg_vorbis_open,
    00640                ogg_vorbis_rewrite,
    00641                ogg_vorbis_write,
    00642                ogg_vorbis_seek,
    00643                ogg_vorbis_trunc,
    00644                ogg_vorbis_tell,
    00645                ogg_vorbis_read,
    00646                ogg_vorbis_close,
    00647                ogg_vorbis_getcomment);
    00648 }
    00649
    00650 int unload_module()
    00651 {
    00652    return ast_format_unregister(name);
    00653 }
    00654
    00655 int usecount()
    00656 {
    00657    return glistcnt;
    00658 }
    00659
    00660 char *description()
    00661 {
    00662    return desc;
    00663 }
    00664
    00665
    00666 char *key()
    00667 {
    00668    return ASTERISK_GPL_KEY;
    00669 }
    00670
    00671 /*
    00672 Local Variables:
    00673 mode: C
    00674 c-file-style: "linux"
    00675 indent-tabs-mode: t
    00676 End:
    00677 */