aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--testing/asterisk/APKBUILD14
-rw-r--r--testing/asterisk/ASTERISK-18976.patch142
-rw-r--r--testing/asterisk/ASTERISK-18977.patch63
-rw-r--r--testing/asterisk/ASTERISK-18994.patch28
-rw-r--r--testing/asterisk/ASTERISK-18995.patch358
5 files changed, 602 insertions, 3 deletions
diff --git a/testing/asterisk/APKBUILD b/testing/asterisk/APKBUILD
index d237a45f0b..0a6c924133 100644
--- a/testing/asterisk/APKBUILD
+++ b/testing/asterisk/APKBUILD
@@ -2,7 +2,7 @@
# Maintainer: Timo Teras <timo.teras@iki.fi>
pkgname=asterisk
pkgver=10.0.0_rc2
-pkgrel=0
+pkgrel=1
pkgdesc="Asterisk: A Module Open Source PBX System"
url="http://www.asterisk.org/"
arch="all"
@@ -11,7 +11,7 @@ depends=
makedepends="autoconf automake libtool ncurses-dev popt-dev newt-dev zlib-dev
postgresql-dev unixodbc-dev dahdi-tools-dev libpri-dev tar
freetds-dev openssl-dev lua-dev alsa-lib-dev spandsp-dev tiff-dev
- libresample sqlite-dev wget speex-dev"
+ libresample sqlite-dev wget speex-dev libogg-dev"
install="$pkgname.pre-install $pkgname.pre-upgrade $pkgname.post-install"
subpackages="$pkgname-dev $pkgname-doc $pkgname-pgsql $pkgname-odbc
$pkgname-tds $pkgname-fax $pkgname-sample-config:sample $pkgname-sqlite
@@ -20,6 +20,10 @@ source="http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-$
100-uclibc-daemon.patch
101-caps-uclibc.patch
400-bug-227.patch
+ ASTERISK-18976.patch
+ ASTERISK-18977.patch
+ ASTERISK-18994.patch
+ ASTERISK-18995.patch
asterisk.initd
asterisk.confd
asterisk.logrotate"
@@ -28,7 +32,7 @@ _builddir="$srcdir/$pkgname-${pkgver/_/-}"
prepare() {
cd "$_builddir"
- for i in ../[1-9]*.patch; do
+ for i in ../[1-9A]*.patch; do
msg "Apply $i"
patch -p1 < $i || return 1
done
@@ -163,6 +167,10 @@ md5sums="72e0df43d5bcf44400dcf0014fd40a3f asterisk-10.0.0-rc2.tar.gz
b00c9d98ce2ad445501248a197c6e436 100-uclibc-daemon.patch
6e1129e30c4fd2c25c86c81685a485a9 101-caps-uclibc.patch
79e9634b5054bceb3b8dc246654bb243 400-bug-227.patch
+da5a3c500192dee4275aae5235d25f97 ASTERISK-18976.patch
+1ddadef41aa7120e168738b6f3ed8917 ASTERISK-18977.patch
+0af5e797f0a99d0f81f95e3710baf5b6 ASTERISK-18994.patch
+bc6713f5434e07b79d3afdd155461d72 ASTERISK-18995.patch
0ce3219e05f55af884a7dc6b99c2b276 asterisk.initd
ed31d7ba37bcf8b0346dcf8593c395f0 asterisk.confd
3e65172275684373e1a25c8a11224411 asterisk.logrotate"
diff --git a/testing/asterisk/ASTERISK-18976.patch b/testing/asterisk/ASTERISK-18976.patch
new file mode 100644
index 0000000000..36c613ff4f
--- /dev/null
+++ b/testing/asterisk/ASTERISK-18976.patch
@@ -0,0 +1,142 @@
+--- a/pbx/pbx_lua.c.orig 2011-12-08 08:28:31.000000000 +0200
++++ b/pbx/pbx_lua.c 2011-12-08 08:54:22.000000000 +0200
+@@ -94,7 +94,6 @@
+ static void lua_create_application_metatable(lua_State *L);
+ static void lua_create_autoservice_functions(lua_State *L);
+ static void lua_create_hangup_function(lua_State *L);
+-static void lua_detect_goto(lua_State *L);
+ static void lua_concat_args(lua_State *L, int start, int nargs);
+
+ static void lua_state_destroy(void *data);
+@@ -213,19 +212,10 @@
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
++ context = ast_strdupa(chan->context);
++ exten = ast_strdupa(chan->exten);
++ priority = chan->priority;
+
+- lua_getfield(L, LUA_REGISTRYINDEX, "context");
+- context = ast_strdupa(lua_tostring(L, -1));
+- lua_pop(L, 1);
+-
+- lua_getfield(L, LUA_REGISTRYINDEX, "exten");
+- exten = ast_strdupa(lua_tostring(L, -1));
+- lua_pop(L, 1);
+-
+- lua_getfield(L, LUA_REGISTRYINDEX, "priority");
+- priority = lua_tointeger(L, -1);
+- lua_pop(L, 1);
+-
+ lua_concat_args(L, 2, nargs);
+ data = lua_tostring(L, -1);
+
+@@ -256,75 +246,51 @@
+ return lua_error(L);
+ }
+
+- lua_detect_goto(L);
+-
+- return 0;
+-}
+-
+-/*!
+- * \brief Detect if a Goto or other dialplan jump has been executed and return
+- * control to the pbx engine.
+- */
+-static void lua_detect_goto(lua_State *L)
+-{
+- struct ast_channel *chan;
+-
+- lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+- chan = lua_touserdata(L, -1);
+- lua_pop(L, 1);
+-
+- /* check context */
+- lua_getfield(L, LUA_REGISTRYINDEX, "context");
+- lua_pushstring(L, chan->context);
+- if (!lua_equal(L, -1, -2)) {
++ if (strcmp(context, chan->context)) {
++ lua_pushstring(L, context);
++ lua_pushstring(L, chan->context);
+ lua_pushliteral(L, "context");
+- goto e_goto_detected;
+- }
+- lua_pop(L, 2);
+-
+- /* check exten */
+- lua_getfield(L, LUA_REGISTRYINDEX, "exten");
+- lua_pushstring(L, chan->exten);
+- if (!lua_equal(L, -1, -2)) {
++ } else if (strcmp(exten, chan->exten)) {
++ lua_pushstring(L, exten);
++ lua_pushstring(L, chan->exten);
+ lua_pushliteral(L, "exten");
+- goto e_goto_detected;
+- }
+- lua_pop(L, 2);
+-
+- /* check priority */
+- lua_getfield(L, LUA_REGISTRYINDEX, "priority");
+- lua_pushinteger(L, chan->priority);
+- if (!lua_equal(L, -1, -2)) {
++ } else if (priority != chan->priority) {
++ lua_pushinteger(L, priority);
++ lua_pushinteger(L, chan->priority);
+ lua_pushliteral(L, "priority");
+- goto e_goto_detected;
++ } else {
++ /* no goto - restore the original position back
++ * to lua state, in case this was a recursive dialplan
++ * call (a dialplan application re-entering dialplan) */
++ lua_update_registry(L, context, exten, priority);
++ return 0;
+ }
+- lua_pop(L, 2);
+- return;
+-
+-e_goto_detected:
+- /* format our debug message */
+- lua_insert(L, -3);
+
+- lua_pushliteral(L, " changed from ");
++ /* goto detected - construct error message */
+ lua_insert(L, -3);
+-
+- lua_pushliteral(L, " to ");
+- lua_insert(L, -2);
+-
+- lua_concat(L, 5);
+-
+- ast_debug(2, "Goto detected: %s\n", lua_tostring(L, -1));
+- lua_pop(L, 1);
+-
+- /* let the lua engine know it needs to return control to the pbx */
+- lua_pushinteger(L, LUA_GOTO_DETECTED);
++
++ lua_pushliteral(L, " changed from ");
++ lua_insert(L, -3);
++
++ lua_pushliteral(L, " to ");
++ lua_insert(L, -2);
++
++ lua_concat(L, 5);
++
++ ast_debug(2, "Goto detected: %s\n", lua_tostring(L, -1));
++ lua_pop(L, 1);
++
++ /* let the lua engine know it needs to return control to the pbx */
++ lua_pushinteger(L, LUA_GOTO_DETECTED);
+ lua_error(L);
++
++ return 0;
+ }
+
+ /*!
+ * \brief [lua_CFunction] Used to get the value of a variable or dialplan
+ * function (for access from lua, don't call directly)
+- *
++ *
+ * The value of the variable or function is returned. This function is the
+ * 'get()' function in the following example as would be seen in
+ * extensions.lua.
diff --git a/testing/asterisk/ASTERISK-18977.patch b/testing/asterisk/ASTERISK-18977.patch
new file mode 100644
index 0000000000..fffce032cd
--- /dev/null
+++ b/testing/asterisk/ASTERISK-18977.patch
@@ -0,0 +1,63 @@
+--- a/res/res_musiconhold.c.orig
++++ b/res/res_musiconhold.c
+@@ -158,6 +158,7 @@
+ char name[MAX_MUSICCLASS];
+ struct ast_format origwfmt;
+ struct ast_format mohwfmt;
++ int announcement;
+ int samples;
+ int sample_queue;
+ int pos;
+@@ -173,6 +174,7 @@
+ #define MOH_SORTALPHA (1 << 4)
+
+ #define MOH_CACHERTCLASSES (1 << 5) /*!< Should we use a separate instance of MOH for each user or not */
++#define MOH_ANNOUNCEMENT (1 << 6)
+
+ /* Custom astobj2 flag */
+ #define MOH_NOTDELETED (1 << 30) /*!< Find only records that aren't deleted? */
+@@ -183,6 +185,7 @@
+ char name[MAX_MUSICCLASS];
+ char dir[256];
+ char args[256];
++ char announcement[80];
+ char mode[80];
+ char digit;
+ /*! A dynamically sized array to hold the list of filenames in "files" mode */
+@@ -278,6 +281,7 @@
+ }
+
+ state->save_pos = state->pos;
++ state->announcement = 0;
+
+ state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
+ }
+@@ -293,6 +297,16 @@
+ chan->stream = NULL;
+ }
+
++ if (ast_test_flag(state->class, MOH_ANNOUNCEMENT) && state->announcement == 0) {
++ state->announcement = 1;
++ if (ast_openstream_full(chan, state->class->announcement, chan->language, 1)) {
++ ast_debug(1, "%s Opened announcement '%s'\n", chan->name, state->class->announcement);
++ return 0;
++ }
++ } else {
++ state->announcement = 0;
++ }
++
+ if (!state->class->total_files) {
+ ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
+ return -1;
+@@ -1731,7 +1745,10 @@
+ ast_copy_string(class->dir, var->value, sizeof(class->dir));
+ else if (!strcasecmp(var->name, "application"))
+ ast_copy_string(class->args, var->value, sizeof(class->args));
+- else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
++ else if (!strcasecmp(var->name, "announcement")) {
++ ast_copy_string(class->announcement, var->value, sizeof(class->announcement));
++ ast_set_flag(class, MOH_ANNOUNCEMENT);
++ } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
+ class->digit = *var->value;
+ else if (!strcasecmp(var->name, "random"))
+ ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
diff --git a/testing/asterisk/ASTERISK-18994.patch b/testing/asterisk/ASTERISK-18994.patch
new file mode 100644
index 0000000000..702e91375d
--- /dev/null
+++ b/testing/asterisk/ASTERISK-18994.patch
@@ -0,0 +1,28 @@
+--- a/main/file.c.orig 2011-12-09 11:32:05.000000000 +0200
++++ b/main/file.c 2011-12-09 11:35:22.000000000 +0200
+@@ -1005,6 +1005,7 @@
+ struct ast_filestream *fs;
+ struct ast_filestream *vfs=NULL;
+ char fmt[256];
++ off_t pos;
+ int seekattempt;
+ int res;
+
+@@ -1017,12 +1018,14 @@
+ /* check to see if there is any data present (not a zero length file),
+ * done this way because there is no where for ast_openstream_full to
+ * return the file had no data. */
+- seekattempt = fseek(fs->f, -1, SEEK_END);
++ pos = ftello(fs->f);
++ seekattempt = fseeko(fs->f, -1, SEEK_END);
+ if (seekattempt && errno == EINVAL) {
+ /* Zero-length file, as opposed to a pipe */
+ return 0;
+- } else {
+- ast_seekstream(fs, 0, SEEK_SET);
++ }
++ if (seekattempt == 0) {
++ fseeko(fs->f, pos, SEEK_SET);
+ }
+
+ vfs = ast_openvstream(chan, filename, preflang);
diff --git a/testing/asterisk/ASTERISK-18995.patch b/testing/asterisk/ASTERISK-18995.patch
new file mode 100644
index 0000000000..cd144847be
--- /dev/null
+++ b/testing/asterisk/ASTERISK-18995.patch
@@ -0,0 +1,358 @@
+--- /dev/null 2011-11-29 09:02:40.279581283 +0200
++++ b/formats/format_ogg_speex.c 2011-12-08 15:57:12.000000000 +0200
+@@ -0,0 +1,355 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2011, Timo Teräs
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*! \file
++ *
++ * \brief OGG/Speex streams.
++ * \arg File name extension: spx
++ * \ingroup formats
++ */
++
++/*** MODULEINFO
++ <depend>speex</depend>
++ <depend>ogg</depend>
++ <support_level>extended</support_level>
++ ***/
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include "asterisk/mod_format.h"
++#include "asterisk/module.h"
++
++#include <speex/speex_header.h>
++#include <ogg/ogg.h>
++
++#define BLOCK_SIZE 4096 /* buffer size for feeding OGG routines */
++#define BUF_SIZE 200
++
++struct speex_desc { /* format specific parameters */
++ /* structures for handling the Ogg container */
++ ogg_sync_state oy;
++ ogg_stream_state os;
++ ogg_page og;
++ ogg_packet op;
++
++ int format_id;
++ int serialno;
++
++ /*! \brief Indicates whether an End of Stream condition has been detected. */
++ int eos;
++};
++
++static int read_packet(struct ast_filestream *fs)
++{
++ struct speex_desc *s = (struct speex_desc *)fs->_private;
++ char *buffer;
++ int result;
++ size_t bytes;
++
++ while (1) {
++ /* Get one packet */
++ result = ogg_stream_packetout(&s->os, &s->op);
++ if (result > 0) {
++ if (s->op.bytes>=5 && !memcmp(s->op.packet, "Speex", 5))
++ s->serialno = s->os.serialno;
++ if (s->serialno == -1 || s->os.serialno != s->serialno)
++ continue;
++ return 0;
++ }
++
++ if (result < 0)
++ ast_log(LOG_WARNING,
++ "Corrupt or missing data at this page position; continuing...\n");
++
++ /* No more packets left in the current page... */
++ if (s->eos) {
++ /* No more pages left in the stream */
++ return -1;
++ }
++
++ while (!s->eos) {
++ /* See if OGG has any pages in it's internal buffers */
++ result = ogg_sync_pageout(&s->oy, &s->og);
++ if (result > 0) {
++ /* Read all streams. */
++ if (ogg_page_serialno(&s->og) != s->os.serialno)
++ ogg_stream_reset_serialno(&s->os, ogg_page_serialno(&s->og));
++ /* Yes, OGG has more pages in it's internal buffers,
++ add the page to the stream state */
++ result = ogg_stream_pagein(&s->os, &s->og);
++ if (result == 0) {
++ /* Yes, got a new,valid page */
++ if (ogg_page_eos(&s->og) &&
++ ogg_page_serialno(&s->og) == s->serialno)
++ s->eos = 1;
++ break;
++ }
++ ast_log(LOG_WARNING,
++ "Invalid page in the bitstream; continuing...\n");
++ }
++
++ if (result < 0)
++ ast_log(LOG_WARNING,
++ "Corrupt or missing data in bitstream; continuing...\n");
++
++ /* No, we need to read more data from the file descrptor */
++ /* get a buffer from OGG to read the data into */
++ buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
++ bytes = fread(buffer, 1, BLOCK_SIZE, fs->f);
++ ogg_sync_wrote(&s->oy, bytes);
++ if (bytes == 0)
++ s->eos = 1;
++ }
++ }
++}
++
++/*!
++ * \brief Create a new OGG/Speex filestream and set it up for reading.
++ * \param fs File that points to on disk storage of the OGG/Speex data.
++ * \param expected_rate The expected Speex format (sampling rate).
++ * \return The new filestream.
++ */
++static int ogg_speex_open(struct ast_filestream *fs, int format_id, int expected_rate)
++{
++ char *buffer;
++ size_t bytes;
++ struct speex_desc *s = (struct speex_desc *)fs->_private;
++ SpeexHeader *hdr = NULL;
++ int i, result;
++
++ s->format_id = format_id;
++ s->serialno = -1;
++ ogg_sync_init(&s->oy);
++
++ buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
++ bytes = fread(buffer, 1, BLOCK_SIZE, fs->f);
++ ogg_sync_wrote(&s->oy, bytes);
++
++ result = ogg_sync_pageout(&s->oy, &s->og);
++ if (result != 1) {
++ if(bytes < BLOCK_SIZE) {
++ ast_log(LOG_ERROR, "Run out of data...\n");
++ } else {
++ ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
++ }
++ ogg_sync_clear(&s->oy);
++ return -1;
++ }
++
++ ogg_stream_init(&s->os, ogg_page_serialno(&s->og));
++ if (ogg_stream_pagein(&s->os, &s->og) < 0) {
++ ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
++ goto error;
++ }
++
++ if (read_packet(fs) < 0) {
++ ast_log(LOG_ERROR, "Error reading initial header packet.\n");
++ goto error;
++ }
++
++ hdr = speex_packet_to_header((char*)s->op.packet, s->op.bytes);
++ if (memcmp(hdr->speex_string, "Speex ", 8)) {
++ ast_log(LOG_ERROR, "OGG container does not contain Speex audio!\n");
++ goto error;
++ }
++ if (hdr->frames_per_packet != 1) {
++ ast_log(LOG_ERROR, "Only one frame-per-packet OGG/Speex files are currently supported!\n");
++ goto error;
++ }
++ if (hdr->nb_channels != 1) {
++ ast_log(LOG_ERROR, "Only monophonic OGG/Speex files are currently supported!\n");
++ goto error;
++ }
++ if (hdr->rate != expected_rate) {
++ ast_log(LOG_ERROR, "Unexpected sampling rate (%d != %d)!\n",
++ hdr->rate, expected_rate);
++ goto error;
++ }
++
++ /* this packet is the comment */
++ if (read_packet(fs) < 0) {
++ ast_log(LOG_ERROR, "Error reading comment packet.\n");
++ goto error;
++ }
++ for (i = 0; i < hdr->extra_headers; i++) {
++ if (read_packet(fs) < 0) {
++ ast_log(LOG_ERROR, "Error reading extra header packet %d.\n", i+1);
++ goto error;
++ }
++ }
++ free(hdr);
++
++ return 0;
++error:
++ if (hdr)
++ free(hdr);
++ ogg_stream_clear(&s->os);
++ ogg_sync_clear(&s->oy);
++ return -1;
++}
++
++/*!
++ * \brief Close a OGG/Speex filestream.
++ * \param fs A OGG/Speex filestream.
++ */
++static void ogg_speex_close(struct ast_filestream *fs)
++{
++ struct speex_desc *s = (struct speex_desc *)fs->_private;
++
++ ogg_stream_clear(&s->os);
++ ogg_sync_clear(&s->oy);
++}
++
++/*!
++ * \brief Read a frame full of audio data from the filestream.
++ * \param fs The filestream.
++ * \param whennext Number of sample times to schedule the next call.
++ * \return A pointer to a frame containing audio data or NULL ifthere is no more audio data.
++ */
++static struct ast_frame *ogg_speex_read(struct ast_filestream *fs,
++ int *whennext)
++{
++ struct speex_desc *s = (struct speex_desc *)fs->_private;
++
++ if (read_packet(fs) < 0)
++ return NULL;
++
++ fs->fr.frametype = AST_FRAME_VOICE;
++ ast_format_set(&fs->fr.subclass.format, s->format_id, 0);
++ fs->fr.mallocd = 0;
++ AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
++ memcpy(fs->fr.data.ptr, s->op.packet, s->op.bytes);
++ fs->fr.datalen = s->op.bytes;
++ fs->fr.samples = *whennext = ast_codec_get_samples(&fs->fr);
++
++ return &fs->fr;
++}
++
++/*!
++ * \brief Trucate an OGG/Speex filestream.
++ * \param s The filestream to truncate.
++ * \return 0 on success, -1 on failure.
++ */
++
++static int ogg_speex_trunc(struct ast_filestream *s)
++{
++ ast_log(LOG_WARNING, "Truncation is not supported on OGG/Speex streams!\n");
++ return -1;
++}
++
++/*!
++ * \brief Seek to a specific position in an OGG/Speex filestream.
++ * \param s The filestream to truncate.
++ * \param sample_offset New position for the filestream, measured in 8KHz samples.
++ * \param whence Location to measure
++ * \return 0 on success, -1 on failure.
++ */
++static int ogg_speex_seek(struct ast_filestream *s, off_t sample_offset, int whence)
++{
++ ast_log(LOG_WARNING, "Seeking is not supported on OGG/Speex streams!\n");
++ return -1;
++}
++
++static off_t ogg_speex_tell(struct ast_filestream *s)
++{
++ ast_log(LOG_WARNING, "Telling is not supported on OGG/Speex streams!\n");
++ return -1;
++}
++
++static int ogg_speex_open_nb(struct ast_filestream *fs)
++{
++ return ogg_speex_open(fs, AST_FORMAT_SPEEX, 8000);
++}
++
++static struct ast_format_def speex_f = {
++ .name = "ogg_speex",
++ .exts = "spx",
++ .open = ogg_speex_open_nb,
++ .seek = ogg_speex_seek,
++ .trunc = ogg_speex_trunc,
++ .tell = ogg_speex_tell,
++ .read = ogg_speex_read,
++ .close = ogg_speex_close,
++ .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
++ .desc_size = sizeof(struct speex_desc),
++};
++
++static int ogg_speex_open_wb(struct ast_filestream *fs)
++{
++ return ogg_speex_open(fs, AST_FORMAT_SPEEX16, 16000);
++}
++
++static struct ast_format_def speex16_f = {
++ .name = "ogg_speex16",
++ .exts = "spx16",
++ .open = ogg_speex_open_wb,
++ .seek = ogg_speex_seek,
++ .trunc = ogg_speex_trunc,
++ .tell = ogg_speex_tell,
++ .read = ogg_speex_read,
++ .close = ogg_speex_close,
++ .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
++ .desc_size = sizeof(struct speex_desc),
++};
++
++static int ogg_speex_open_uwb(struct ast_filestream *fs)
++{
++ return ogg_speex_open(fs, AST_FORMAT_SPEEX32, 32000);
++}
++
++static struct ast_format_def speex32_f = {
++ .name = "ogg_speex32",
++ .exts = "spx32",
++ .open = ogg_speex_open_uwb,
++ .seek = ogg_speex_seek,
++ .trunc = ogg_speex_trunc,
++ .tell = ogg_speex_tell,
++ .read = ogg_speex_read,
++ .close = ogg_speex_close,
++ .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
++ .desc_size = sizeof(struct speex_desc),
++};
++
++static int load_module(void)
++{
++ ast_format_set(&speex_f.format, AST_FORMAT_SPEEX, 0);
++ ast_format_set(&speex16_f.format, AST_FORMAT_SPEEX16, 0);
++ ast_format_set(&speex32_f.format, AST_FORMAT_SPEEX32, 0);
++
++ if (ast_format_def_register(&speex_f) ||
++ ast_format_def_register(&speex16_f) ||
++ ast_format_def_register(&speex32_f))
++ return AST_MODULE_LOAD_FAILURE;
++
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++static int unload_module(void)
++{
++ int res = 0;
++ res |= ast_format_def_unregister(speex_f.name);
++ res |= ast_format_def_unregister(speex16_f.name);
++ res |= ast_format_def_unregister(speex32_f.name);
++ return res;
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "OGG/Speex audio",
++ .load = load_module,
++ .unload = unload_module,
++ .load_pri = AST_MODPRI_APP_DEPEND
++);