aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2012-09-05 11:50:40 +0300
committerTimo Teräs <timo.teras@iki.fi>2012-09-05 11:53:13 +0300
commite41af81a83fd767c98c8c5bdba7def5da868163b (patch)
tree7751b089cbb2e4473c2c5193b06799f2f99b364c
parentf5ea352121c614e1abdd86e67ba9c8c3827eb653 (diff)
downloadaports-e41af81a83fd767c98c8c5bdba7def5da868163b.tar.bz2
aports-e41af81a83fd767c98c8c5bdba7def5da868163b.tar.xz
testing/asterisk: fork main/asterisk and upgrade to 11.0.0-beta1
* remove patches upstreamed ASTERISK-18977 and 900-tryinclude.patch * add ASTERISK-20362 required to fix parallel compile issues * rebase the ConfBridge 'deaf participant' patch ASTERISK-19109
-rw-r--r--testing/asterisk/100-uclibc-daemon.patch44
-rw-r--r--testing/asterisk/101-caps-uclibc.patch17
-rw-r--r--testing/asterisk/102-gsm-pic.patch54
-rw-r--r--testing/asterisk/APKBUILD191
-rw-r--r--testing/asterisk/ASTERISK-18995.patch358
-rw-r--r--testing/asterisk/ASTERISK-19109.patch724
-rw-r--r--testing/asterisk/ASTERISK-20362.patch30
-rw-r--r--testing/asterisk/asterisk.confd91
-rw-r--r--testing/asterisk/asterisk.initd251
-rw-r--r--testing/asterisk/asterisk.logrotate17
-rw-r--r--testing/asterisk/asterisk.pre-install6
-rw-r--r--testing/asterisk/asterisk.pre-upgrade6
12 files changed, 1789 insertions, 0 deletions
diff --git a/testing/asterisk/100-uclibc-daemon.patch b/testing/asterisk/100-uclibc-daemon.patch
new file mode 100644
index 0000000000..4956791d4d
--- /dev/null
+++ b/testing/asterisk/100-uclibc-daemon.patch
@@ -0,0 +1,44 @@
+diff -Nru asterisk-1.6.1-beta4.org/main/asterisk.c asterisk-1.6.1-beta4/main/asterisk.c
+--- asterisk-1.6.1-beta4.org/main/asterisk.c 2008-12-12 23:05:58.000000000 +0100
++++ asterisk-1.6.1-beta4/main/asterisk.c 2008-12-23 15:28:21.000000000 +0100
+@@ -3295,9 +3295,40 @@
+ #if HAVE_WORKING_FORK
+ if (ast_opt_always_fork || !ast_opt_no_fork) {
+ #ifndef HAVE_SBIN_LAUNCHD
++#ifndef __UCLIBC__
+ if (daemon(1, 0) < 0) {
+ ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
+ }
++#else
++ /*
++ * workaround for uClibc-0.9.29 mipsel bug:
++ * recursive mutexes do not work if uClibc daemon() function has been called,
++ * if parent thread locks a mutex
++ * the child thread cannot acquire a lock with the same name
++ * (same code works if daemon() is not called)
++ * but duplication of uClibc daemon.c code in here does work.
++ */
++ int fd;
++ switch (fork()) {
++ case -1:
++ exit(1);
++ case 0:
++ break;
++ default:
++ _exit(0);
++ }
++ if (setsid() == -1)
++ exit(1);
++ if (fork())
++ _exit(0);
++ if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
++ dup2(fd, STDIN_FILENO);
++ dup2(fd, STDOUT_FILENO);
++ dup2(fd, STDERR_FILENO);
++ if (fd > 2)
++ close(fd);
++ }
++#endif
+ ast_mainpid = getpid();
+ /* Blindly re-write pid file since we are forking */
+ unlink(ast_config_AST_PID);
diff --git a/testing/asterisk/101-caps-uclibc.patch b/testing/asterisk/101-caps-uclibc.patch
new file mode 100644
index 0000000000..bb32d1ece1
--- /dev/null
+++ b/testing/asterisk/101-caps-uclibc.patch
@@ -0,0 +1,17 @@
+--- asterisk-1.6.0.18/configure.ac.orig Mon Oct 26 23:13:28 2009
++++ asterisk-1.6.0.18/configure.ac Fri Nov 27 21:42:36 2009
+@@ -627,9 +627,11 @@
+
+ AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
+
+-if test "x${OSARCH}" = "xlinux-gnu" ; then
+- AST_EXT_LIB_CHECK([CAP], [cap], [cap_from_text], [sys/capability.h])
+-fi
++case "${OSARCH}" in
++ linux*)
++ AST_EXT_LIB_CHECK([CAP], [cap], [cap_from_text], [sys/capability.h])
++ ;;
++esac
+
+ AST_C_DEFINE_CHECK([DAHDI], [DAHDI_CODE], [dahdi/user.h])
+
diff --git a/testing/asterisk/102-gsm-pic.patch b/testing/asterisk/102-gsm-pic.patch
new file mode 100644
index 0000000000..71370ec0b7
--- /dev/null
+++ b/testing/asterisk/102-gsm-pic.patch
@@ -0,0 +1,54 @@
+--- a/codecs/gsm/Makefile.org 2008-03-29 11:33:09.000000000 +0100
++++ b/codecs/gsm/Makefile 2008-03-29 11:44:40.000000000 +0100
+@@ -37,23 +37,6 @@
+ ######### ppro's, etc, as well as the AMD K6 and K7. The compile will
+ ######### probably require gcc.
+
+-ifeq (, $(findstring $(OSARCH) , Darwin SunOS ))
+-ifeq (, $(findstring $(PROC) , x86_64 amd64 ultrasparc sparc64 arm armv5b armeb ppc powerpc ppc64 ia64 s390 bfin mipsel mips))
+-ifeq (, $(findstring $(shell uname -m) , ppc ppc64 alpha armv4l s390 ))
+-OPTIMIZE+=-march=$(PROC)
+-endif
+-endif
+-endif
+-
+-#The problem with sparc is the best stuff is in newer versions of gcc (post 3.0) only.
+-#This works for even old (2.96) versions of gcc and provides a small boost either way.
+-#A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesn't support it.
+-#So we go lowest common available by gcc and go a step down, still a step up from
+-#the default as we now have a better instruction set to work with. - Belgarath
+-ifeq ($(PROC),ultrasparc)
+-OPTIMIZE+=-mcpu=v8 -mtune=$(PROC) -O3
+-endif
+-
+ PG =
+ #PG = -g -pg
+ ######### Profiling flags. If you don't know what that means, leave it blank.
+@@ -208,12 +191,10 @@
+ # XXX Keep a space after each findstring argument
+ # XXX should merge with GSM_OBJECTS
+ ifeq ($(OSARCH),linux-gnu)
+-ifeq (,$(findstring $(shell uname -m) , x86_64 amd64 ppc ppc64 alpha armv4l sparc64 parisc s390 ))
+-ifeq (,$(findstring $(PROC) , arm armv5b armeb powerpc ia64 s390 bfin mipsel mips ))
++ifneq ($(K6OPT),)
+ GSM_SOURCES+= $(SRC)/k6opt.s
+ endif
+ endif
+-endif
+
+ TOAST_SOURCES = $(SRC)/toast.c \
+ $(SRC)/toast_lin.c \
+@@ -260,12 +241,10 @@
+ $(SRC)/table.o
+
+ ifeq ($(OSARCH),linux-gnu)
+-ifeq (,$(findstring $(shell uname -m) , x86_64 amd64 ppc ppc64 alpha armv4l sparc64 parisc ))
+-ifeq (,$(findstring $(PROC) , arm armv5b armeb powerpc ia64 bfin mipsel mips ))
++ifneq ($(K6OPT),)
+ GSM_OBJECTS+= $(SRC)/k6opt.o
+ endif
+ endif
+-endif
+
+ TOAST_OBJECTS = $(SRC)/toast.o \
+ $(SRC)/toast_lin.o \
diff --git a/testing/asterisk/APKBUILD b/testing/asterisk/APKBUILD
new file mode 100644
index 0000000000..82768e994c
--- /dev/null
+++ b/testing/asterisk/APKBUILD
@@ -0,0 +1,191 @@
+# Contributor: Timo Teras <timo.teras@iki.fi>
+# Maintainer: Timo Teras <timo.teras@iki.fi>
+pkgname=asterisk
+pkgver=11.0.0_beta1
+pkgrel=0
+pkgdesc="Asterisk: A Module Open Source PBX System"
+pkgusers="asterisk"
+pkggroups="asterisk"
+url="http://www.asterisk.org/"
+arch="all"
+license="GPL"
+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 libogg-dev bluez-dev"
+install="$pkgname.pre-install $pkgname.pre-upgrade"
+subpackages="$pkgname-dev $pkgname-doc $pkgname-pgsql $pkgname-odbc
+ $pkgname-tds $pkgname-fax $pkgname-sample-config:sample
+ $pkgname-sounds-moh:sound_moh $pkgname-sounds-en:sound_en
+ $pkgname-mobile"
+source="http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-${pkgver/_/-}.tar.gz
+ 100-uclibc-daemon.patch
+ 101-caps-uclibc.patch
+ ASTERISK-18995.patch
+ ASTERISK-19109.patch
+ ASTERISK-20362.patch
+ asterisk.initd
+ asterisk.confd
+ asterisk.logrotate"
+
+_builddir="$srcdir/$pkgname-${pkgver/_/-}"
+
+prepare() {
+ cd "$_builddir"
+ for i in ../[1-9A]*.patch; do
+ msg "Apply $i"
+ patch -p1 < $i || return 1
+ done
+
+ sed -i -e 's:lua5.1/::' pbx/pbx_lua.c
+ sed -i -e 's/PBX_ICONV=1/PBX_ICONV=0/g' configure.ac
+ sed -i -e 's/int foo = res_ninit(NULL);/res_ninit_is_not_really_here();/g' configure.ac
+
+ ./bootstrap.sh
+}
+
+build() {
+ cd "$_builddir"
+ SHA1SUM="$PWD"/build_tools/sha1sum-sh ./configure --prefix=/usr \
+ --sysconfdir=/etc \
+ --mandir=/usr/share/man \
+ --infodir=/usr/share/info \
+ --libdir=/usr/lib \
+ --localstatedir=/var \
+ --disable-xmldoc --with-gsm=internal \
+ --without-iconv --with-popt --with-z --with-newt \
+ --with-unixodbc --with-postgres --with-tds \
+ --with-dahdi --with-pri --with-tonezone \
+ --with-resample \
+ --with-sqlite3 \
+ --with-speex \
+ --with-asound \
+ --without-x11 \
+ --with-spandsp \
+ --with-bluetooth \
+ || return 1
+
+ # and figure out which modules to build
+ rm menuselect.makeopts
+ make menuselect.makeopts
+ # enable chan_mobile
+ sed -i -e '/^MENUSELECT_ADDONS=/s/chan_mobile//' menuselect.makeopts
+ make ASTCFLAGS="$CFLAGS" ASTLDFLAGS="$LDFLAGS" || return 1
+}
+
+package() {
+ cd "$_builddir"
+ make -j1 DESTDIR="$pkgdir" install
+
+ install -d "$pkgdir"/var/run/asterisk
+ install -d "$pkgdir"/var/lib/asterisk
+
+ install -m755 -D "$srcdir"/$pkgname.initd "$pkgdir"/etc/init.d/$pkgname
+ install -m644 -D "$srcdir"/$pkgname.confd "$pkgdir"/etc/conf.d/$pkgname
+ install -m644 -D "$srcdir"/$pkgname.logrotate \
+ "$pkgdir"/etc/logrotate.d/$pkgname
+
+ chown -R asterisk:asterisk "$pkgdir"/var/*/asterisk
+ chown -R asterisk:asterisk "$pkgdir"/etc/asterisk
+ chmod -R u=rwX,g=rX,o= "$pkgdir"/etc/asterisk
+}
+
+_move_dir() {
+ for DIR in "$@"; do
+ local dest=`dirname "$subpkgdir/$DIR"`
+ echo mkdir -p $dest
+ mkdir -p "$dest"
+ echo mv "$pkgdir"/$DIR $dest
+ mv "$pkgdir"/"$DIR" "$dest"
+ done
+}
+
+_find_and_move() {
+ local pattern="$1"
+ cd "$pkgdir" || return 1
+ find -name "$pattern" -type f | while read f; do
+ local dest="$subpkgdir/${f%/*}"
+ mkdir -p "$dest"
+ mv "$f" "$dest"
+ done
+}
+
+doc() {
+ default_doc
+}
+
+dev() {
+ default_dev
+ depends="asterisk"
+}
+
+pgsql() {
+ depends=
+ install=
+ _find_and_move '*_pgsql*'
+}
+
+odbc() {
+ depends=
+ install=
+ _find_and_move '*odbc*'
+}
+
+tds() {
+ depends=
+ install=
+ _find_and_move '*_tds*'
+}
+
+fax() {
+ depends=
+ install=
+ _find_and_move '*_fax*'
+}
+
+mobile() {
+ depends=
+ install=
+ _find_and_move '*_mobile*'
+}
+
+sample() {
+ arch="noarch"
+ pkgdesc="Sample configuration files for asterisk"
+ cd "$_builddir"
+ mkdir -p "$subpkgdir"/var/lib/asterisk/phoneprov
+ make -j1 samples DESTDIR="$subpkgdir"
+
+ chown -R asterisk:asterisk "$subpkgdir"/var/*/asterisk
+ chown -R asterisk:asterisk "$subpkgdir"/etc/asterisk
+ chmod -R u=rwX,g=rX,o= "$subpkgdir"/etc/asterisk
+}
+
+sound_moh() {
+ arch="noarch"
+ pkgdesc="Default on-hold music files for asterisk"
+ depends=
+ install=
+ _move_dir var/lib/asterisk/moh
+ chown -R asterisk:asterisk "$subpkgdir"/var/*/asterisk
+}
+
+sound_en() {
+ arch="noarch"
+ pkgdesc="English sound files for asterisk"
+ depends=
+ install=
+ _move_dir var/lib/asterisk/sounds/en
+ chown -R asterisk:asterisk "$subpkgdir"/var/*/asterisk
+}
+
+md5sums="a99bdeae82f80b25b093eba957581dd9 asterisk-11.0.0-beta1.tar.gz
+b00c9d98ce2ad445501248a197c6e436 100-uclibc-daemon.patch
+6e1129e30c4fd2c25c86c81685a485a9 101-caps-uclibc.patch
+bc6713f5434e07b79d3afdd155461d72 ASTERISK-18995.patch
+146befabe95798a67c58d8ac00d397a6 ASTERISK-19109.patch
+491aa86a1b3b6d1b9c8dd72314e9859f ASTERISK-20362.patch
+74cd25a5638a94ef51e9f4ede2fd28f2 asterisk.initd
+ed31d7ba37bcf8b0346dcf8593c395f0 asterisk.confd
+3e65172275684373e1a25c8a11224411 asterisk.logrotate"
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
++);
diff --git a/testing/asterisk/ASTERISK-19109.patch b/testing/asterisk/ASTERISK-19109.patch
new file mode 100644
index 0000000000..cd45b42731
--- /dev/null
+++ b/testing/asterisk/ASTERISK-19109.patch
@@ -0,0 +1,724 @@
+From 806946c35cf0560248e63fea53c4d82426a2034a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
+Date: Wed, 5 Sep 2012 10:07:05 +0300
+Subject: [PATCH] ASTERISK-19109: Implement deaf participant support for
+ ConfBridge
+
+---
+ CHANGES | 3 +
+ apps/app_confbridge.c | 218 ++++++++++++++++++++++++++++++---
+ apps/confbridge/conf_config_parser.c | 14 +++
+ apps/confbridge/include/confbridge.h | 6 +
+ bridges/bridge_multiplexed.c | 2 +-
+ bridges/bridge_simple.c | 2 +-
+ bridges/bridge_softmix.c | 38 +++---
+ configs/confbridge.conf.sample | 5 +
+ include/asterisk/bridging_features.h | 2 +
+ include/asterisk/bridging_technology.h | 15 +++
+ main/bridging.c | 22 ++++
+ 11 files changed, 294 insertions(+), 33 deletions(-)
+
+diff --git a/CHANGES b/CHANGES
+index c3c9891..2efa17b 100644
+--- a/CHANGES
++++ b/CHANGES
+@@ -66,6 +66,9 @@ ConfBridge
+ file will be played to the user, and only the user, upon joining the
+ conference bridge.
+
++ * Added support for deaf participants with CLI commands, manager actions
++ and ConfBridge DTMF actions to toggle the deaf state.
++
+
+ Dial
+ -------------------
+diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c
+index 90954b8..0455be4 100644
+--- a/apps/app_confbridge.c
++++ b/apps/app_confbridge.c
+@@ -185,6 +185,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ <description>
+ </description>
+ </manager>
++ <manager name="ConfbridgeDeafen" language="en_US">
++ <synopsis>
++ Deafen a Confbridge user.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Conference" required="true" />
++ <parameter name="Channel" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="ConfbridgeUndeafen" language="en_US">
++ <synopsis>
++ Undeafen a Confbridge user.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Conference" required="true" />
++ <parameter name="Channel" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
+ <manager name="ConfbridgeKick" language="en_US">
+ <synopsis>
+ Kick a Confbridge user.
+@@ -273,6 +297,13 @@ static const char app[] = "ConfBridge";
+ /* Number of buckets our conference bridges container can have */
+ #define CONFERENCE_BRIDGE_BUCKETS 53
+
++enum confbridge_feature_action {
++ CONFBRIDGE_FEATURE_MUTE,
++ CONFBRIDGE_FEATURE_UNMUTE,
++ CONFBRIDGE_FEATURE_DEAFEN,
++ CONFBRIDGE_FEATURE_UNDEAFEN
++};
++
+ /*! \brief Container to hold all conference bridges in progress */
+ static struct ao2_container *conference_bridges;
+
+@@ -311,6 +342,10 @@ const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds
+ return S_OR(custom_sounds->muted, "conf-muted");
+ case CONF_SOUND_UNMUTED:
+ return S_OR(custom_sounds->unmuted, "conf-unmuted");
++ case CONF_SOUND_DEAFENED:
++ return S_OR(custom_sounds->deafened, "conf-deafened");
++ case CONF_SOUND_UNDEAFENED:
++ return S_OR(custom_sounds->undeafened, "conf-undeafened");
+ case CONF_SOUND_ONLY_ONE:
+ return S_OR(custom_sounds->onlyone, "conf-onlyone");
+ case CONF_SOUND_THERE_ARE:
+@@ -1504,10 +1539,13 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
+ volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
+ volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
+
+- /* If the caller should be joined already muted, make it so */
++ /* If the caller should be joined already muted or deaf, make it so */
+ if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_STARTMUTED)) {
+ conference_bridge_user.features.mute = 1;
+ }
++ if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_STARTDEAF)) {
++ conference_bridge_user.features.deaf = 1;
++ }
+
+ if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DROP_SILENCE)) {
+ conference_bridge_user.tech_args.drop_silence = 1;
+@@ -1668,6 +1706,20 @@ static int action_toggle_mute_participants(struct conference_bridge *conference_
+ return 0;
+ }
+
++static int action_toggle_deaf(struct conference_bridge *conference_bridge,
++ struct conference_bridge_user *conference_bridge_user,
++ struct ast_channel *chan)
++{
++ /* Deafen or undeafen yourself */
++ conference_bridge_user->features.deaf = (!conference_bridge_user->features.deaf ? 1 : 0);
++ ast_test_suite_event_notify("CONF_DEAF", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", chan->name, conference_bridge_user->features.deaf ? "deafened" : "undeafened", conference_bridge_user->b_profile.name, chan->name);
++
++ return ast_stream_and_wait(chan, (conference_bridge_user->features.deaf ?
++ conf_get_sound(CONF_SOUND_DEAFENED, conference_bridge_user->b_profile.sounds) :
++ conf_get_sound(CONF_SOUND_UNDEAFENED, conference_bridge_user->b_profile.sounds)),
++ "");
++}
++
+ static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file)
+ {
+ char *file_copy = ast_strdupa(playback_file);
+@@ -1856,6 +1908,11 @@ static int execute_menu_entry(struct conference_bridge *conference_bridge,
+ case MENU_ACTION_PARTICIPANT_COUNT:
+ announce_user_count(conference_bridge, conference_bridge_user);
+ break;
++ case MENU_ACTION_TOGGLE_DEAF:
++ res |= action_toggle_deaf(conference_bridge,
++ conference_bridge_user,
++ bridge_channel->chan);
++ break;
+ case MENU_ACTION_PLAYBACK:
+ if (!stop_prompts) {
+ res |= action_playback(bridge_channel, menu_action->data.playback_file);
+@@ -2119,13 +2176,13 @@ static int generic_lock_unlock_helper(int lock, const char *conference)
+ }
+
+ /* \internal
+- * \brief finds a conference user by channel name and mutes/unmutes them.
++ * \brief finds a conference user by channel name and changes feature bits on it.
+ *
+ * \retval 0 success
+ * \retval -1 conference not found
+ * \retval -2 user not found
+ */
+-static int generic_mute_unmute_helper(int mute, const char *conference, const char *user)
++static int generic_feature_action_helper(enum confbridge_feature_action action, const char *conference, const char *user)
+ {
+ struct conference_bridge *bridge = NULL;
+ struct conference_bridge tmp;
+@@ -2143,10 +2200,44 @@ static int generic_mute_unmute_helper(int mute, const char *conference, const ch
+ }
+ }
+ if (participant) {
+- participant->features.mute = mute;
+- ast_test_suite_event_notify("CONF_MUTE", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", ast_channel_name(participant->chan), participant->features.mute ? "muted" : "unmuted", bridge->b_profile.name, ast_channel_name(participant->chan));
++ const char *state, *verb;
++
++ switch (action) {
++ case CONFBRIDGE_FEATURE_DEAFEN:
++ participant->features.deaf = 1;
++ state = "CONF_DEAF";
++ verb = "deafened";
++ break;
++ case CONFBRIDGE_FEATURE_UNDEAFEN:
++ participant->features.deaf = 0;
++ state = "CONF_DEAF";
++ verb = "undeafened";
++ break;
++ case CONFBRIDGE_FEATURE_MUTE:
++ participant->features.mute = 1;
++ state = "CONF_MUTE";
++ verb = "muted";
++ break;
++ case CONFBRIDGE_FEATURE_UNMUTE:
++ default:
++ participant->features.mute = 0;
++ state = "CONF_MUTE";
++ verb = "unmuted";
++ break;
++ }
++
++ if (state != NULL && verb != NULL) {
++ ast_test_suite_event_notify(state,
++ "Message: participant %s %s\r\n"
++ "Conference: %s\r\n"
++ "Channel: %s",
++ ast_channel_name(participant->chan),
++ verb,
++ bridge->b_profile.name,
++ ast_channel_name(participant->chan));
++ }
+ } else {
+- res = -2;;
++ res = -2;
+ }
+ ao2_unlock(bridge);
+ ao2_ref(bridge, -1);
+@@ -2154,9 +2245,10 @@ static int generic_mute_unmute_helper(int mute, const char *conference, const ch
+ return res;
+ }
+
+-static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
++static int cli_feature_action_helper(enum confbridge_feature_action action, struct ast_cli_args *a)
+ {
+- int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]);
++ const char *verb;
++ int res = generic_feature_action_helper(action, a->argv[2], a->argv[3]);
+
+ if (res == -1) {
+ ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
+@@ -2165,7 +2257,24 @@ static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
+ ast_cli(a->fd, "No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
+ return -1;
+ }
+- ast_cli(a->fd, "%s %s from confbridge %s\n", mute ? "Muting" : "Unmuting", a->argv[3], a->argv[2]);
++
++ switch (action) {
++ case CONFBRIDGE_FEATURE_DEAFEN:
++ verb = "Deafening";
++ break;
++ case CONFBRIDGE_FEATURE_UNDEAFEN:
++ verb = "Undeafening";
++ break;
++ case CONFBRIDGE_FEATURE_MUTE:
++ verb = "Muting";
++ break;
++ case CONFBRIDGE_FEATURE_UNMUTE:
++ default:
++ verb = "Unmuting";
++ break;
++ }
++
++ ast_cli(a->fd, "%s %s from confbridge %s\n", verb, a->argv[3], a->argv[2]);
+ return 0;
+ }
+
+@@ -2187,7 +2296,7 @@ static char *handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct
+ return CLI_SHOWUSAGE;
+ }
+
+- cli_mute_unmute_helper(1, a);
++ cli_feature_action_helper(CONFBRIDGE_FEATURE_MUTE, a);
+
+ return CLI_SUCCESS;
+ }
+@@ -2210,7 +2319,53 @@ static char *handle_cli_confbridge_unmute(struct ast_cli_entry *e, int cmd, stru
+ return CLI_SHOWUSAGE;
+ }
+
+- cli_mute_unmute_helper(0, a);
++ cli_feature_action_helper(CONFBRIDGE_FEATURE_UNMUTE, a);
++
++ return CLI_SUCCESS;
++}
++
++static char *handle_cli_confbridge_deafen(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "confbridge deafen";
++ e->usage =
++ "Usage: confbridge deafen <conference> <channel>\n";
++ return NULL;
++ case CLI_GENERATE:
++ if (a->pos == 2) {
++ return complete_confbridge_name(a->line, a->word, a->pos, a->n);
++ }
++ return NULL;
++ }
++ if (a->argc != 4) {
++ return CLI_SHOWUSAGE;
++ }
++
++ cli_feature_action_helper(CONFBRIDGE_FEATURE_DEAFEN, a);
++
++ return CLI_SUCCESS;
++}
++
++static char *handle_cli_confbridge_undeafen(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "confbridge undeafen";
++ e->usage =
++ "Usage: confbridge undeafen <conference> <channel>\n";
++ return NULL;
++ case CLI_GENERATE:
++ if (a->pos == 2) {
++ return complete_confbridge_name(a->line, a->word, a->pos, a->n);
++ }
++ return NULL;
++ }
++ if (a->argc != 4) {
++ return CLI_SHOWUSAGE;
++ }
++
++ cli_feature_action_helper(CONFBRIDGE_FEATURE_UNDEAFEN, a);
+
+ return CLI_SUCCESS;
+ }
+@@ -2358,6 +2513,8 @@ static struct ast_cli_entry cli_confbridge[] = {
+ AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges."),
+ AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute a participant."),
+ AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute a participant."),
++ AST_CLI_DEFINE(handle_cli_confbridge_deafen, "Deafen a participant."),
++ AST_CLI_DEFINE(handle_cli_confbridge_undeafen, "Undeafen a participant."),
+ AST_CLI_DEFINE(handle_cli_confbridge_lock, "Lock a conference."),
+ AST_CLI_DEFINE(handle_cli_confbridge_unlock, "Unlock a conference."),
+ AST_CLI_DEFINE(handle_cli_confbridge_start_record, "Start recording a conference"),
+@@ -2492,10 +2649,11 @@ static int action_confbridgelistrooms(struct mansession *s, const struct message
+ return 0;
+ }
+
+-static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute)
++static int action_feature_action_helper(struct mansession *s, const struct message *m, enum confbridge_feature_action action)
+ {
+ const char *conference = astman_get_header(m, "Conference");
+ const char *channel = astman_get_header(m, "Channel");
++ char *verb;
+ int res = 0;
+
+ if (ast_strlen_zero(conference)) {
+@@ -2511,7 +2669,7 @@ static int action_mute_unmute_helper(struct mansession *s, const struct message
+ return 0;
+ }
+
+- res = generic_mute_unmute_helper(mute, conference, channel);
++ res = generic_feature_action_helper(action, conference, channel);
+
+ if (res == -1) {
+ astman_send_error(s, m, "No Conference by that name found.");
+@@ -2521,17 +2679,41 @@ static int action_mute_unmute_helper(struct mansession *s, const struct message
+ return 0;
+ }
+
+- astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
++ switch (action) {
++ case CONFBRIDGE_FEATURE_DEAFEN:
++ verb = "User deafened";
++ break;
++ case CONFBRIDGE_FEATURE_UNDEAFEN:
++ verb = "User undeafened";
++ break;
++ case CONFBRIDGE_FEATURE_MUTE:
++ verb = "User muted";
++ break;
++ case CONFBRIDGE_FEATURE_UNMUTE:
++ default:
++ verb = "User unmuted";
++ break;
++ }
++
++ astman_send_ack(s, m, verb);
+ return 0;
+ }
+
+ static int action_confbridgeunmute(struct mansession *s, const struct message *m)
+ {
+- return action_mute_unmute_helper(s, m, 0);
++ return action_feature_action_helper(s, m, CONFBRIDGE_FEATURE_UNMUTE);
+ }
+ static int action_confbridgemute(struct mansession *s, const struct message *m)
+ {
+- return action_mute_unmute_helper(s, m, 1);
++ return action_feature_action_helper(s, m, CONFBRIDGE_FEATURE_MUTE);
++}
++static int action_confbridgeundeafen(struct mansession *s, const struct message *m)
++{
++ return action_feature_action_helper(s, m, CONFBRIDGE_FEATURE_UNDEAFEN);
++}
++static int action_confbridgedeafen(struct mansession *s, const struct message *m)
++{
++ return action_feature_action_helper(s, m, CONFBRIDGE_FEATURE_DEAFEN);
+ }
+
+ static int action_lock_unlock_helper(struct mansession *s, const struct message *m, int lock)
+@@ -2818,6 +3000,8 @@ static int unload_module(void)
+ res |= ast_manager_unregister("ConfbridgeListRooms");
+ res |= ast_manager_unregister("ConfbridgeMute");
+ res |= ast_manager_unregister("ConfbridgeUnmute");
++ res |= ast_manager_unregister("ConfbridgeDeafen");
++ res |= ast_manager_unregister("ConfbridgeUndeafen");
+ res |= ast_manager_unregister("ConfbridgeKick");
+ res |= ast_manager_unregister("ConfbridgeUnlock");
+ res |= ast_manager_unregister("ConfbridgeLock");
+@@ -2860,6 +3044,8 @@ static int load_module(void)
+ res |= ast_manager_register_xml("ConfbridgeListRooms", EVENT_FLAG_REPORTING, action_confbridgelistrooms);
+ res |= ast_manager_register_xml("ConfbridgeMute", EVENT_FLAG_CALL, action_confbridgemute);
+ res |= ast_manager_register_xml("ConfbridgeUnmute", EVENT_FLAG_CALL, action_confbridgeunmute);
++ res |= ast_manager_register_xml("ConfbridgeDeafen", EVENT_FLAG_CALL, action_confbridgedeafen);
++ res |= ast_manager_register_xml("ConfbridgeUndeafen", EVENT_FLAG_CALL, action_confbridgeundeafen);
+ res |= ast_manager_register_xml("ConfbridgeKick", EVENT_FLAG_CALL, action_confbridgekick);
+ res |= ast_manager_register_xml("ConfbridgeUnlock", EVENT_FLAG_CALL, action_confbridgeunlock);
+ res |= ast_manager_register_xml("ConfbridgeLock", EVENT_FLAG_CALL, action_confbridgelock);
+diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c
+index f4a9604..8a02de7 100644
+--- a/apps/confbridge/conf_config_parser.c
++++ b/apps/confbridge/conf_config_parser.c
+@@ -279,6 +279,10 @@ static int set_sound(const char *sound_name, const char *sound_file, struct brid
+ ast_string_field_set(sounds, muted, sound_file);
+ } else if (!strcasecmp(sound_name, "sound_unmuted")) {
+ ast_string_field_set(sounds, unmuted, sound_file);
++ } else if (!strcasecmp(sound_name, "sound_deafened")) {
++ ast_string_field_set(sounds, deafened, sound_file);
++ } else if (!strcasecmp(sound_name, "sound_undeafened")) {
++ ast_string_field_set(sounds, undeafened, sound_file);
+ } else if (!strcasecmp(sound_name, "sound_there_are")) {
+ ast_string_field_set(sounds, thereare, sound_file);
+ } else if (!strcasecmp(sound_name, "sound_other_in_party")) {
+@@ -418,6 +422,7 @@ static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum con
+ switch (id) {
+ case MENU_ACTION_NOOP:
+ case MENU_ACTION_TOGGLE_MUTE:
++ case MENU_ACTION_TOGGLE_DEAF:
+ case MENU_ACTION_INCREASE_LISTENING:
+ case MENU_ACTION_DECREASE_LISTENING:
+ case MENU_ACTION_INCREASE_TALKING:
+@@ -708,6 +713,9 @@ static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, in
+ ast_cli(a->fd,"Start Muted: %s\n",
+ u_profile.flags & USER_OPT_STARTMUTED?
+ "true" : "false");
++ ast_cli(a->fd,"Start Deaf: %s\n",
++ u_profile.flags & USER_OPT_STARTDEAF?
++ "true" : "false");
+ ast_cli(a->fd,"MOH When Empty: %s\n",
+ u_profile.flags & USER_OPT_MUSICONHOLD ?
+ "enabled" : "disabled");
+@@ -896,6 +904,8 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e,
+ ast_cli(a->fd,"sound_kicked: %s\n", conf_get_sound(CONF_SOUND_KICKED, b_profile.sounds));
+ ast_cli(a->fd,"sound_muted: %s\n", conf_get_sound(CONF_SOUND_MUTED, b_profile.sounds));
+ ast_cli(a->fd,"sound_unmuted: %s\n", conf_get_sound(CONF_SOUND_UNMUTED, b_profile.sounds));
++ ast_cli(a->fd,"sound_deafened: %s\n", conf_get_sound(CONF_SOUND_DEAFENED, b_profile.sounds));
++ ast_cli(a->fd,"sound_undeafened: %s\n", conf_get_sound(CONF_SOUND_UNDEAFENED, b_profile.sounds));
+ ast_cli(a->fd,"sound_there_are: %s\n", conf_get_sound(CONF_SOUND_THERE_ARE, b_profile.sounds));
+ ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds));
+ ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds));
+@@ -1021,6 +1031,9 @@ static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, s
+ case MENU_ACTION_TOGGLE_MUTE:
+ ast_cli(a->fd, "toggle_mute");
+ break;
++ case MENU_ACTION_TOGGLE_DEAF:
++ ast_cli(a->fd, "toggle_deaf");
++ break;
+ case MENU_ACTION_NOOP:
+ ast_cli(a->fd, "no_op");
+ break;
+@@ -1268,6 +1281,7 @@ int conf_load_config(int reload)
+ aco_option_register(&cfg_info, "admin", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ADMIN);
+ aco_option_register(&cfg_info, "marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MARKEDUSER);
+ aco_option_register(&cfg_info, "startmuted", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTMUTED);
++ aco_option_register(&cfg_info, "startdeaf", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTDEAF);
+ aco_option_register(&cfg_info, "music_on_hold_when_empty", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MUSICONHOLD);
+ aco_option_register(&cfg_info, "quiet", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_QUIET);
+ aco_option_register_custom(&cfg_info, "announce_user_count_all", ACO_EXACT, user_types, "no", announce_user_count_all_handler, 0);
+diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h
+index d3ead35..3d773c5 100644
+--- a/apps/confbridge/include/confbridge.h
++++ b/apps/confbridge/include/confbridge.h
+@@ -57,6 +57,7 @@ enum user_profile_flags {
+ USER_OPT_DTMF_PASS = (1 << 13), /*!< Sets if dtmf should be passed into the conference or not */
+ USER_OPT_ANNOUNCEUSERCOUNTALL = (1 << 14), /*!< Sets if the number of users should be announced to everyone. */
+ USER_OPT_JITTERBUFFER = (1 << 15), /*!< Places a jitterbuffer on the user. */
++ USER_OPT_STARTDEAF = (1 << 16), /*!< Set if the caller should be initially set deaf */
+ };
+
+ enum bridge_profile_flags {
+@@ -68,6 +69,7 @@ enum bridge_profile_flags {
+
+ enum conf_menu_action_id {
+ MENU_ACTION_TOGGLE_MUTE = 1,
++ MENU_ACTION_TOGGLE_DEAF,
+ MENU_ACTION_PLAYBACK,
+ MENU_ACTION_PLAYBACK_AND_CONTINUE,
+ MENU_ACTION_INCREASE_LISTENING,
+@@ -142,6 +144,8 @@ enum conf_sounds {
+ CONF_SOUND_KICKED,
+ CONF_SOUND_MUTED,
+ CONF_SOUND_UNMUTED,
++ CONF_SOUND_DEAFENED,
++ CONF_SOUND_UNDEAFENED,
+ CONF_SOUND_ONLY_ONE,
+ CONF_SOUND_THERE_ARE,
+ CONF_SOUND_OTHER_IN_PARTY,
+@@ -168,6 +172,8 @@ struct bridge_profile_sounds {
+ AST_STRING_FIELD(kicked);
+ AST_STRING_FIELD(muted);
+ AST_STRING_FIELD(unmuted);
++ AST_STRING_FIELD(deafened);
++ AST_STRING_FIELD(undeafened);
+ AST_STRING_FIELD(onlyone);
+ AST_STRING_FIELD(thereare);
+ AST_STRING_FIELD(otherinparty);
+diff --git a/bridges/bridge_multiplexed.c b/bridges/bridge_multiplexed.c
+index cd30266..190f790 100644
+--- a/bridges/bridge_multiplexed.c
++++ b/bridges/bridge_multiplexed.c
+@@ -386,7 +386,7 @@ static enum ast_bridge_write_result multiplexed_bridge_write(struct ast_bridge *
+ }
+
+ if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+- ast_write(other->chan, frame);
++ ast_bridge_handle_channel_write(bridge, other, frame);
+ }
+
+ return AST_BRIDGE_WRITE_SUCCESS;
+diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c
+index 69e4114..1623ce0 100644
+--- a/bridges/bridge_simple.c
++++ b/bridges/bridge_simple.c
+@@ -81,7 +81,7 @@ static enum ast_bridge_write_result simple_bridge_write(struct ast_bridge *bridg
+
+ /* Write the frame out if they are in the waiting state... don't worry about freeing it, the bridging core will take care of it */
+ if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+- ast_write(other->chan, frame);
++ ast_bridge_handle_channel_write(bridge, other, frame);
+ }
+
+ return AST_BRIDGE_WRITE_SUCCESS;
+diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
+index 52e5551..5754e41 100644
+--- a/bridges/bridge_softmix.c
++++ b/bridges/bridge_softmix.c
+@@ -435,7 +435,7 @@ static void softmix_pass_dtmf(struct ast_bridge *bridge, struct ast_bridge_chann
+ if (tmp == bridge_channel) {
+ continue;
+ }
+- ast_write(tmp->chan, frame);
++ ast_bridge_handle_channel_write(bridge, tmp, frame);
+ }
+ }
+
+@@ -447,7 +447,7 @@ static void softmix_pass_video_top_priority(struct ast_bridge *bridge, struct as
+ continue;
+ }
+ if (ast_bridge_is_video_src(bridge, tmp->chan) == 1) {
+- ast_write(tmp->chan, frame);
++ ast_bridge_handle_channel_write(bridge, tmp, frame);
+ break;
+ }
+ }
+@@ -463,7 +463,7 @@ static void softmix_pass_video_all(struct ast_bridge *bridge, struct ast_bridge_
+ if ((tmp->chan == bridge_channel->chan) && !echo) {
+ continue;
+ }
+- ast_write(tmp->chan, frame);
++ ast_bridge_handle_channel_write(bridge, tmp, frame);
+ }
+ }
+
+@@ -563,7 +563,7 @@ static enum ast_bridge_write_result softmix_bridge_write(struct ast_bridge *brid
+
+ /* If a frame is ready to be written out, do so */
+ if (sc->have_frame) {
+- ast_write(bridge_channel->chan, &sc->write_frame);
++ ast_bridge_handle_channel_write(bridge, bridge_channel, &sc->write_frame);
+ sc->have_frame = 0;
+ }
+
+@@ -582,7 +582,7 @@ bridge_write_cleanup:
+ * the conference to the channel. */
+ ast_mutex_lock(&sc->lock);
+ if (sc->have_frame) {
+- ast_write(bridge_channel->chan, &sc->write_frame);
++ ast_bridge_handle_channel_write(bridge, bridge_channel, &sc->write_frame);
+ sc->have_frame = 0;
+ }
+ ast_mutex_unlock(&sc->lock);
+@@ -598,7 +598,7 @@ static int softmix_bridge_poke(struct ast_bridge *bridge, struct ast_bridge_chan
+ ast_mutex_lock(&sc->lock);
+
+ if (sc->have_frame) {
+- ast_write(bridge_channel->chan, &sc->write_frame);
++ ast_bridge_handle_channel_write(bridge, bridge_channel, &sc->write_frame);
+ sc->have_frame = 0;
+ }
+
+@@ -850,16 +850,24 @@ static int softmix_bridge_thread(struct ast_bridge *bridge)
+
+ ast_mutex_lock(&sc->lock);
+
+- /* Make SLINEAR write frame from local buffer */
+- if (sc->write_frame.subclass.format.id != cur_slin_id) {
+- ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0);
++ if (bridge->features.deaf ||
++ (bridge_channel->features && bridge_channel->features->deaf)) {
++ /* For deaf channels post a null frame */
++ sc->write_frame.frametype = AST_FRAME_NULL;
++ } else {
++ /* Make SLINEAR write frame from local buffer */
++ sc->write_frame.frametype = AST_FRAME_VOICE;
++ if (sc->write_frame.subclass.format.id != cur_slin_id) {
++ ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0);
++ }
++ sc->write_frame.datalen = softmix_datalen;
++ sc->write_frame.samples = softmix_samples;
++ memcpy(sc->final_buf, buf, softmix_datalen);
++
++ /* process the softmix channel's new write audio */
++ softmix_process_write_audio(&trans_helper,
++ ast_channel_rawwriteformat(bridge_channel->chan), sc);
+ }
+- sc->write_frame.datalen = softmix_datalen;
+- sc->write_frame.samples = softmix_samples;
+- memcpy(sc->final_buf, buf, softmix_datalen);
+-
+- /* process the softmix channel's new write audio */
+- softmix_process_write_audio(&trans_helper, ast_channel_rawwriteformat(bridge_channel->chan), sc);
+
+ /* The frame is now ready for use... */
+ sc->have_frame = 1;
+diff --git a/configs/confbridge.conf.sample b/configs/confbridge.conf.sample
+index 7484b28..3b0ce85 100644
+--- a/configs/confbridge.conf.sample
++++ b/configs/confbridge.conf.sample
+@@ -16,6 +16,7 @@ type=user
+ ;admin=yes ; Sets if the user is an admin or not. Off by default.
+ ;marked=yes ; Sets if this is a marked user or not. Off by default.
+ ;startmuted=yes; Sets if all users should start out muted. Off by default
++;startdeaf=yes ; Sets if all users should start out deaf. Off by default.
+ ;music_on_hold_when_empty=yes ; Sets whether MOH should be played when only
+ ; one person is in the conference or when the
+ ; the user is waiting on a marked user to enter
+@@ -210,6 +211,8 @@ type=bridge
+ ;sound_kicked ; The sound played to a user who has been kicked from the conference.
+ ;sound_muted ; The sound played when the mute option it toggled on.
+ ;sound_unmuted ; The sound played when the mute option it toggled off.
++;sound_deafened ; The sound played when the deaf option is toggled on.
++;sound_undeafened ; The sound played when the deaf option is toggled off.
+ ;sound_only_person ; The sound played when the user is the only person in the conference.
+ ;sound_only_one ; The sound played to a user when there is only one other
+ ; person is in the conference.
+@@ -264,6 +267,8 @@ type=bridge
+ ; toggle_mute ; Toggle turning on and off mute. Mute will make the user silent
+ ; to everyone else, but the user will still be able to listen in.
+ ; continue to collect the dtmf sequence.
++; toggle_deaf ; Toggle turning on and off deaf. Deaf will make the user to hear
++ ; only silence, but the user will still be able to talk.
+ ; no_op ; This action does nothing (No Operation). Its only real purpose exists for
+ ; being able to reserve a sequence in the config as a menu exit sequence.
+ ; decrease_listening_volume ; Decreases the channel's listening volume.
+diff --git a/include/asterisk/bridging_features.h b/include/asterisk/bridging_features.h
+index e377ca6..5ce3d56 100644
+--- a/include/asterisk/bridging_features.h
++++ b/include/asterisk/bridging_features.h
+@@ -127,6 +127,8 @@ struct ast_bridge_features {
+ unsigned int usable:1;
+ /*! Bit to indicate whether the channel/bridge is muted or not */
+ unsigned int mute:1;
++ /*! Bit to indicate whether the channel/bridge is deaf or not */
++ unsigned int deaf:1;
+ /*! Bit to indicate whether DTMF should be passed into the bridge tech or not. */
+ unsigned int dtmf_passthrough:1;
+
+diff --git a/include/asterisk/bridging_technology.h b/include/asterisk/bridging_technology.h
+index 3d2e870..1ecb4c1 100644
+--- a/include/asterisk/bridging_technology.h
++++ b/include/asterisk/bridging_technology.h
+@@ -143,6 +143,21 @@ int ast_bridge_technology_unregister(struct ast_bridge_technology *technology);
+ */
+ void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_channel *chan, int outfd);
+
++/*! \brief Used by bridging technologies to hand off a frame to be written to a bridge_channel.
++ *
++ * \param bridge The bridge that the channel is part of.
++ * \param bridge_channel The bridge channel to which the frame is written to.
++ * \param frame The frame to write.
++ *
++ * \retval 0 on success
++ * \retval -1 on failure
++ *
++ * \note This function is essentially a wrapper for ast_write(). The bridging core has some features associated with it
++ * that requires it to have control over how frames are written into a channel. For these features to be available, the bridging
++ * technology must use this wrapper function over ast_write when pushing a frame out a channel.
++ */
++int ast_bridge_handle_channel_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame);
++
+ /*! \brief Lets the bridging indicate when a bridge channel has stopped or started talking.
+ *
+ * \note All DSP functionality on the bridge has been pushed down to the lowest possible
+diff --git a/main/bridging.c b/main/bridging.c
+index 465d033..4f67e90 100644
+--- a/main/bridging.c
++++ b/main/bridging.c
+@@ -337,6 +337,28 @@ void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel
+ return;
+ }
+
++int ast_bridge_handle_channel_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
++{
++ if (frame->frametype == AST_FRAME_VOICE &&
++ (bridge->features.deaf ||
++ (bridge_channel->features && bridge_channel->features->deaf))) {
++ short buf[frame->samples];
++ struct ast_frame sframe = {
++ .frametype = AST_FRAME_VOICE,
++ .data.ptr = buf,
++ .samples = frame->samples,
++ .datalen = sizeof(buf),
++ };
++ ast_format_set(&sframe.subclass.format, AST_FORMAT_SLINEAR, 0);
++ memset(buf, 0, sizeof(buf));
++
++ return ast_write(bridge_channel->chan, &sframe);
++ }
++
++ return ast_write(bridge_channel->chan, frame);
++}
++
++
+ /*! \brief Generic thread loop, TODO: Rethink this/improve it */
+ static int generic_thread_loop(struct ast_bridge *bridge)
+ {
+--
+1.7.12
+
diff --git a/testing/asterisk/ASTERISK-20362.patch b/testing/asterisk/ASTERISK-20362.patch
new file mode 100644
index 0000000000..a64489784d
--- /dev/null
+++ b/testing/asterisk/ASTERISK-20362.patch
@@ -0,0 +1,30 @@
+diff --git a/res/Makefile b/res/Makefile
+index bfbca76..c2ad23b 100644
+--- a/res/Makefile
++++ b/res/Makefile
+@@ -67,17 +67,20 @@ endif
+ ael/pval.o: ael/pval.c
+
+ clean::
++ ${MAKE} -C pjproject clean
+ rm -f snmp/*.o snmp/*.i ael/*.o ael/*.i ais/*.o ais/*.i
+
+ pjproject/build.mak:
+ cd pjproject && ./configure AR="" CFLAGS=-fPIC --disable-floating-point --disable-sound --disable-oss --disable-speex-aec --disable-l16-codec --disable-gsm-codec --disable-g722-codec --disable-g7221-codec --disable-speex-codec --disable-ilbc-codec --disable-g711-codec
+
+-include pjproject/build.mak
++pjproject.stamp: pjproject/build.mak
++ ${MAKE} -j1 -C pjproject dep
++ ${MAKE} -j1 -C pjproject
++ touch pjproject.stamp
+
+-res_rtp_asterisk.o: pjproject/build.mak $(PJ_LIB_FILES)
++-include pjproject/build.mak
++
++res_rtp_asterisk.o: pjproject.stamp
+ res_rtp_asterisk.o: _ASTCFLAGS+=$(PJ_CFLAGS)
+ res_rtp_asterisk.so: _ASTLDFLAGS+=$(PJ_LDFLAGS)
+ res_rtp_asterisk.so: LIBS+=$(PJ_LDLIBS)
+-
+-$(PJ_LIB_FILES):
+- cd pjproject && make dep && make
diff --git a/testing/asterisk/asterisk.confd b/testing/asterisk/asterisk.confd
new file mode 100644
index 0000000000..fe9f138ab7
--- /dev/null
+++ b/testing/asterisk/asterisk.confd
@@ -0,0 +1,91 @@
+#
+# Additional options for asterisk
+#
+# see "asterisk -h" for a list of options
+#
+ASTERISK_OPTS=""
+
+#
+# User and group to run asterisk as
+#
+# Value: double-colon separated list of user and group, or empty to run as root:
+#
+#
+# "asterisk:asterisk" to run as user "asterisk" and group "asterisk"
+# "asterisk" to run as user "asterisk" and all groups that user "asterisk" is a member of
+# ":asterisk" to run as user "root" and group "asterisk"
+# "" to run as user "root" and group "root"
+#
+ASTERISK_USER="asterisk"
+
+#
+# Nicelevel
+#
+# Set the priority of the asterisk process
+#
+# Value: (highest) -20..19 (lowest)
+#
+#ASTERISK_NICE="19"
+
+#
+# Wrapper script
+#
+# Value: yes or no/empty
+#
+ASTERISK_WRAPPER="no"
+
+############# Wrapper script settings #############
+
+#
+# Send crash notifications emails to this address
+# (needs a working mail service and /usr/sbin/sendmail to do so (e.g. ssmtp))
+#
+# Value: Email address or empty to disable
+#
+#ASTERISK_NOTIFY_EMAIL="root"
+
+#
+# Send asterisk's output to this terminal
+#
+# Value: Full path to device node or a number
+#
+#ASTERISK_TTY="/dev/tty9"
+
+#
+# Start an asterisk console on the terminal specified by ASTERISK_TTY
+#
+# Warning! Use only for debugging, this is a potential security issue!
+#
+# Value: yes or no/empty
+#
+ASTERISK_CONSOLE="no"
+
+#
+# Maximum size of core files.
+#
+# Value: Size in bytes, unlimited for no limit or empty to disable.
+#
+#ASTERISK_CORE_SIZE="unlimited"
+
+#
+# ASTERISK_CORE_DIR
+#
+# Value: Directory (will be created if non-existant), default is /tmp
+#
+ASTERISK_CORE_DIR="/var/lib/asterisk/coredump"
+
+#
+# Max number of filedescriptors
+#
+# Value: Number of descriptors
+#
+#ASTERISK_MAX_FD="1024"
+
+#
+# Kill these tasks after asterisk crashed (ASTERISK_WRAPPER=yes only!)
+#
+# Warning! This will kill _ALL_ tasks with the specified names!
+#
+# Value: Space separated list of names in double quotes (e.g. "mpg123 mad")
+#
+#ASTERISK_CLEANUP_ON_CRASH="mpg123 asterisk-mpg123 mad"
diff --git a/testing/asterisk/asterisk.initd b/testing/asterisk/asterisk.initd
new file mode 100644
index 0000000000..9b6c93ecc1
--- /dev/null
+++ b/testing/asterisk/asterisk.initd
@@ -0,0 +1,251 @@
+#!/sbin/runscript
+
+extra_started_commands="forcestop reload"
+
+depend() {
+ need net
+ after firewall
+ use nscd dns zaptel mysql postgresql slapd capi
+}
+
+is_running() {
+ if [ -z "$(pidof asterisk)" ]; then
+ return 1
+ else
+ PID="$(cat /var/run/asterisk/asterisk.pid 2>/dev/null)"
+ for x in $(pidof asterisk); do
+ if [ "${x}" = "${PID}" ]; then
+ return 0
+ fi
+ done
+ fi
+
+ return 1
+}
+
+asterisk_run_loop() {
+ local OPTS ARGS MSG NICE=""
+ local result=0 signal=0
+
+ # default options
+ OPTS="-f" # don't fork / detach breaks wrapper script...
+
+ # filter (redundant) arguments
+ ARGS="$(echo "${@}" | sed -e "s:-c\|-f::g")"
+
+ # mangle yes/no options
+ ASTERISK_CONSOLE="$(echo ${ASTERISK_CONSOLE} | tr '[:lower:]' '[:upper:]')"
+
+ if [ -n "${ASTERISK_CORE_SIZE}" ] &&
+ [ "${ASTERISK_CORE_SIZE}" != "0" ]; then
+ ulimit -c ${ASTERISK_CORE_SIZE}
+
+ if [ -n "${ASTERISK_CORE_DIR}" ] && \
+ [ ! -d "${ASTERISK_CORE_DIR}" ]
+ then
+ mkdir -m750 -p "${ASTERISK_CORE_DIR}"
+
+ if [ -n "${ASTERISK_USER}" ]; then
+ chown -R "${ASTERISK_USER}" "${ASTERISK_CORE_DIR}"
+ fi
+ fi
+ ASTERISK_CORE_DIR="${ASTERISK_CORE_DIR:-/tmp}"
+
+ cd "${ASTERISK_CORE_DIR}"
+ echo " Core dump size : ${ASTERISK_CORE_SIZE}"
+ echo " Core dump location : ${ASTERISK_CORE_DIR}"
+ fi
+
+ if [ -n "${ASTERISK_MAX_FD}" ]; then
+ ulimit -n ${ASTERISK_MAX_FD}
+ echo " Max open filedescriptors : ${ASTERISK_MAX_FD}"
+ fi
+
+ if [ -n "${ASTERISK_NICE}" ]; then
+ echo " Nice level : ${ASTERISK_NICE}"
+ NICE="nice -n ${ASTERISK_NICE} --"
+ fi
+
+ if [ -n "${ASTERISK_NOTIFY_EMAIL}" ]; then
+ if [ -x /usr/sbin/sendmail ]; then
+ echo " Email notifications go to : ${ASTERISK_NOTIFY_EMAIL}"
+ else
+ echo " Notifications disabled, /usr/sbin/sendmail doesn't exist or is not executable!"
+ unset ASTERISK_NOTIFY_EMAIL
+ fi
+ fi
+
+ if [ -n "${ASTERISK_TTY}" ]; then
+ for x in ${ASTERISK_TTY} \
+ /dev/tty${ASTERISK_TTY} \
+ /dev/vc/${ASTERISK_TTY}
+ do
+ if [ -c "${x}" ]; then
+ TTY="${x}"
+ fi
+ done
+ [ -n "${TTY}" ] && \
+ echo " Messages are sent to : ${TTY}"
+ fi
+
+ if [ "${ASTERISK_CONSOLE}" = "YES" ] && [ -n "${TTY}" ]; then
+ echo " Starting Asterisk console : ${ASTERISK_CONSOLE}"
+ OPTS="${OPTS} -c"
+ fi
+
+ OPTS="${OPTS} ${ARGS}"
+
+ while :; do
+
+ if [ -n "${TTY}" ]; then
+ /usr/bin/stty -F ${TTY} sane
+ ${NICE} /usr/sbin/asterisk ${OPTS} >${TTY} 2>&1 <${TTY}
+ result=$?
+ else
+ ${NICE} /usr/sbin/asterisk ${OPTS} &>/dev/null
+ result=$?
+ fi
+
+ if [ $result -eq 0 ]; then
+ echo "Asterisk terminated normally"
+ break
+ else
+ if [ $result -gt 128 ]; then
+ signal=$((result - 128))
+ MSG="Asterisk terminated with Signal: $signal"
+
+ CORE_TARGET="core-$(date "+%Y%m%d-%h%M%s")"
+
+ local CORE_DUMPED=0
+ if [ -f "${ASTERISK_CORE_DIR}/core" ]; then
+ mv "${ASTERISK_CORE_DIR}/core" \
+ "${ASTERISK_CORE_DIR}/${CORE_TARGET}"
+ CORE_DUMPED=1
+
+ elif [ -f "${ASTERISK_CORE_DIR}/core.${PID}" ]; then
+ mv "${ASTERISK_CORE_DIR}/core.${PID}" \
+ "${ASTERISK_CORE_DIR}/${CORE_TARGET}"
+ CORE_DUMPED=1
+
+ fi
+
+ [ $CORE_DUMPED -eq 1 ] && \
+ MSG="${MSG}\n\rCore dumped: ${ASTERISK_CORE_DIR}/${CORE_TARGET}"
+ else
+ MSG="Asterisk terminated with return code: $result"
+ fi
+
+ # kill left-over tasks
+ for X in ${ASTERISK_CLEANUP_ON_CRASH}; do
+ kill -9 $(pidof ${X});
+ done
+ fi
+
+ [ -n "${TTY}" ] \
+ && echo "${MSG}" >${TTY} \
+ || echo "${MSG}"
+
+
+ if [ -n "${ASTERISK_NOTIFY_EMAIL}" ] && \
+ [ -x /usr/sbin/sendmail ]; then
+ echo -e -n "Subject: Asterisk crashed\n\r${MSG}\n\r" |\
+ /usr/sbin/sendmail "${ASTERISK_NOTIFY_EMAIL}"
+ fi
+ sleep 5
+ echo "Restarting Asterisk..."
+ done
+ return 0
+}
+
+start() {
+ local OPTS USER GROUP PID
+ local tmp x
+
+ if [ -n "${ASTERISK_NICE}" ]; then
+ if [ ${ASTERISK_NICE} -ge -20 ] && \
+ [ ${ASTERISK_NICE} -le 19 ]; then
+ OPTS="--nicelevel ${ASTERISK_NICE}"
+ else
+ eerror "Nice value must be between -20 and 19"
+ return 1
+ fi
+ fi
+
+ if [ -n "${ASTERISK_USER}" ]; then
+ USER=$(echo $ASTERISK_USER | sed 's/:.*//')
+ GROUP=$(echo $ASTERISK_USER | awk -F: '/.*:.*/ { print $2 }')
+ if [ -n "${USER}" ]; then
+ ASTERISK_OPTS="${ASTERISK_OPTS} -U ${USER}"
+ fi
+ if [ -n "${GROUP}" ]; then
+ ASTERISK_OPTS="${ASTERISK_OPTS} -G ${GROUP}"
+ GROUP=":${GROUP}" # make it look nice...
+ fi
+ ebegin "Starting asterisk PBX (as ${USER}${GROUP})"
+ else
+ ebegin "Starting asterisk PBX (as root)"
+ fi
+
+ if [ "$(echo ${ASTERISK_WRAPPER} | tr '[:upper:]' '[:lower:]')" != "yes" ]; then
+ start-stop-daemon --start --exec /usr/sbin/asterisk \
+ ${OPTS} -- ${ASTERISK_OPTS}
+ result=$?
+ else
+ asterisk_run_loop ${ASTERISK_OPTS} 2>/dev/null &
+ result=$?
+ fi
+
+ if [ $result -eq 0 ]; then
+ # 2 seconds should be enough for asterisk to start
+ sleep 2
+ is_running
+ result=$?
+ fi
+
+ eend $result
+}
+
+forcestop() {
+ ebegin "Stopping asterisk PBX"
+ start-stop-daemon --stop --pidfile /var/run/asterisk/asterisk.pid
+ eend $?
+}
+
+stop() {
+ if ! is_running; then
+ eerror "Asterisk is not running!"
+ return 0
+ fi
+
+ ebegin "Stopping asterisk PBX now"
+ /usr/sbin/asterisk -r -x "core stop now" &>/dev/null
+ # Now we have to wait until asterisk has _really_ stopped.
+ sleep 1
+ if is_running; then
+ einfon "Waiting for asterisk to shutdown ."
+ local cnt=0
+ while is_running; do
+ cnt=`expr $cnt + 1`
+ if [ $cnt -gt 60 ] ; then
+ # Waited 120 seconds now. Fail.
+ echo
+ eend 1 "Failed."
+ return
+ fi
+ sleep 2
+ echo -n "."
+ done
+ echo
+ fi
+ eend 0
+}
+
+reload() {
+ if is_running; then
+ ebegin "Reloading asterisk configuration"
+ /usr/sbin/asterisk -r -x "core reload" &>/dev/null
+ eend $?
+ else
+ eerror "Asterisk is not running!"
+ fi
+}
diff --git a/testing/asterisk/asterisk.logrotate b/testing/asterisk/asterisk.logrotate
new file mode 100644
index 0000000000..30836c5c11
--- /dev/null
+++ b/testing/asterisk/asterisk.logrotate
@@ -0,0 +1,17 @@
+/var/log/asterisk/messages /var/log/asterisk/*log {
+ missingok
+ rotate 5
+ weekly
+ create 0640 asterisk asterisk
+ postrotate
+ /usr/sbin/asterisk -rx 'logger reload' > /dev/null 2> /dev/null
+ endscript
+}
+
+/var/log/asterisk/cdr-csv/*csv {
+ missingok
+ rotate 5
+ monthly
+ create 0640 asterisk asterisk
+}
+
diff --git a/testing/asterisk/asterisk.pre-install b/testing/asterisk/asterisk.pre-install
new file mode 100644
index 0000000000..6c2984ae4e
--- /dev/null
+++ b/testing/asterisk/asterisk.pre-install
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+adduser -S -h /var/lib/asterisk -s /bin/false -D asterisk 2>/dev/null
+addgroup -S dialout 2>/dev/null
+addgroup asterisk dialout 2>/dev/null
+exit 0
diff --git a/testing/asterisk/asterisk.pre-upgrade b/testing/asterisk/asterisk.pre-upgrade
new file mode 100644
index 0000000000..6c2984ae4e
--- /dev/null
+++ b/testing/asterisk/asterisk.pre-upgrade
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+adduser -S -h /var/lib/asterisk -s /bin/false -D asterisk 2>/dev/null
+addgroup -S dialout 2>/dev/null
+addgroup asterisk dialout 2>/dev/null
+exit 0