Merge "res_pjsip: New endpoint option "refer_blind_progress""
[asterisk/asterisk.git] / res / res_agi.c
index 486310d..e8497f7 100644 (file)
@@ -22,7 +22,6 @@
  *
  * \author Mark Spencer <markster@digium.com>
  *
- * \todo Convert the rest of the AGI commands over to XML documentation
  */
 
 /*** MODULEINFO
@@ -31,8 +30,6 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include <math.h>
 #include <signal.h>
 #include <sys/time.h>
@@ -68,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/netsock2.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/stasis_message_router.h"
+#include "asterisk/format_cache.h"
 
 #define AST_API_MODULE
 #include "asterisk/agi.h"
@@ -84,6 +82,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </description>
                <see-also>
                        <ref type="agi">hangup</ref>
+                       <ref type="application">AGI</ref>
                </see-also>
        </agi>
        <agi name="asyncagi break" language="en_US">
@@ -97,6 +96,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </description>
                <see-also>
                        <ref type="agi">hangup</ref>
+                       <ref type="application">AGI</ref>
                </see-also>
        </agi>
        <agi name="channel status" language="en_US">
@@ -137,6 +137,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                </enum>
                        </enumlist>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="control stream file" language="en_US">
                <synopsis>
@@ -149,19 +152,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <parameter name="escape_digits" required="true" />
                        <parameter name="skipms" />
                        <parameter name="ffchar">
-                               <para>Defaults to <literal>*</literal></para>
+                               <para>Defaults to <literal>#</literal></para>
                        </parameter>
                        <parameter name="rewchr">
-                               <para>Defaults to <literal>#</literal></para>
+                               <para>Defaults to <literal>*</literal></para>
                        </parameter>
                        <parameter name="pausechr" />
+                       <parameter name="offsetms">
+                               <para>Offset, in milliseconds, to start the audio playback</para>
+                       </parameter>
                </syntax>
                <description>
                        <para>Send the given file, allowing playback to be controlled by the given
                        digits, if any. Use double quotes for the digits if you wish none to be
-                       permitted. Returns <literal>0</literal> if playback completes without a digit
+                       permitted. If offsetms is provided then the audio will seek to offsetms
+                       before play starts. Returns <literal>0</literal> if playback completes without a digit
                        being pressed, or the ASCII numerical value of the digit if one was pressed,
-                       or <literal>-1</literal> on error or if the channel was disconnected.</para>
+                       or <literal>-1</literal> on error or if the channel was disconnected. Returns the
+                       position where playback was terminated as endpos.</para>
+
                        <para>It sets the following channel variables upon completion:</para>
                        <variablelist>
                                <variable name="CPLAYBACKSTATUS">
@@ -181,6 +190,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                </variable>
                        </variablelist>
                </description>
+               <see-also>
+                       <ref type="agi">get option</ref>
+                       <ref type="agi">control stream file</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="database del" language="en_US">
                <synopsis>
@@ -196,6 +210,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Returns <literal>1</literal> if successful, <literal>0</literal>
                        otherwise.</para>
                </description>
+               <see-also>
+                       <ref type="agi">database get</ref>
+                       <ref type="agi">database put</ref>
+                       <ref type="agi">database deltree</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="database deltree" language="en_US">
                <synopsis>
@@ -210,6 +230,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        within a <replaceable>family</replaceable> in the Asterisk database.</para>
                        <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
                </description>
+               <see-also>
+                       <ref type="agi">database get</ref>
+                       <ref type="agi">database put</ref>
+                       <ref type="agi">database del</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="database get" language="en_US">
                <synopsis>
@@ -227,6 +253,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        in parenthesis.</para>
                        <para>Example return code: 200 result=1 (testvariable)</para>
                </description>
+               <see-also>
+                       <ref type="agi">database put</ref>
+                       <ref type="agi">database del</ref>
+                       <ref type="agi">database deltree</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="database put" language="en_US">
                <synopsis>
@@ -243,6 +275,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <replaceable>value</replaceable>.</para>
                        <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
                </description>
+               <see-also>
+                       <ref type="agi">database get</ref>
+                       <ref type="agi">database del</ref>
+                       <ref type="agi">database deltree</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="exec" language="en_US">
                <synopsis>
@@ -258,6 +296,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Returns whatever the <replaceable>application</replaceable> returns, or
                        <literal>-2</literal> on failure to find <replaceable>application</replaceable>.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="get data" language="en_US">
                <synopsis>
@@ -272,6 +313,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Stream the given <replaceable>file</replaceable>, and receive DTMF data.</para>
                        <para>Returns the digits received from the channel at the other end.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="get full variable" language="en_US">
                <synopsis>
@@ -288,6 +332,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        variables, unlike GET VARIABLE.</para>
                        <para>Example return code: 200 result=1 (testvariable)</para>
                </description>
+               <see-also>
+                       <ref type="agi">get variable</ref>
+                       <ref type="agi">set variable</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="get option" language="en_US">
                <synopsis>
@@ -303,6 +352,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </description>
                <see-also>
                        <ref type="agi">stream file</ref>
+                       <ref type="agi">control stream file</ref>
+                       <ref type="application">AGI</ref>
                </see-also>
        </agi>
        <agi name="get variable" language="en_US">
@@ -318,6 +369,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        the variable in parentheses.</para>
                        <para>Example return code: 200 result=1 (testvariable)</para>
                </description>
+               <see-also>
+                       <ref type="agi">get full variable</ref>
+                       <ref type="agi">set variable</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="hangup" language="en_US">
                <synopsis>
@@ -330,6 +386,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Hangs up the specified channel. If no channel name is given, hangs
                        up the current channel</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="noop" language="en_US">
                <synopsis>
@@ -339,6 +398,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Does nothing.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="receive char" language="en_US">
                <synopsis>
@@ -356,6 +418,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        if one is received, or <literal>0</literal> if the channel does not support
                        text reception. Returns <literal>-1</literal> only on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">receive text</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="receive text" language="en_US">
                <synopsis>
@@ -368,23 +434,49 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        </parameter>
                </syntax>
                <description>
-                       <para>Receives a string of text on a channel. Most channels 
+                       <para>Receives a string of text on a channel. Most channels
                        do not support the reception of text. Returns <literal>-1</literal> for failure
-                       or <literal>1</literal> for success, and the string in parenthesis.</para> 
+                       or <literal>1</literal> for success, and the string in parenthesis.</para>
                </description>
+               <see-also>
+                       <ref type="agi">receive char</ref>
+                       <ref type="agi">send text</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="record file" language="en_US">
                <synopsis>
                        Records to a given file.
                </synopsis>
                <syntax>
-                       <parameter name="filename" required="true" />
-                       <parameter name="format" required="true" />
-                       <parameter name="escape_digits" required="true" />
-                       <parameter name="timeout" required="true" />
-                       <parameter name="offset samples" />
-                       <parameter name="BEEP" />
-                       <parameter name="s=silence" />
+                       <parameter name="filename" required="true">
+                               <para>The destination filename of the recorded audio.</para>
+                       </parameter>
+                       <parameter name="format" required="true">
+                               <para>The audio format in which to save the resulting file.</para>
+                       </parameter>
+                       <parameter name="escape_digits" required="true">
+                               <para>The DTMF digits that will terminate the recording process.</para>
+                       </parameter>
+                       <parameter name="timeout" required="true">
+                               <para>The maximum recording time in milliseconds. Set to -1 for no
+                               limit.</para>
+                       </parameter>
+                       <parameter name="offset_samples">
+                               <para>Causes the recording to first seek to the specified offset before
+                               recording begins.</para>
+                       </parameter>
+                       <parameter name="beep">
+                               <para>Causes Asterisk to play a beep as recording begins. This argument
+                               can take any value.</para>
+                       </parameter>
+                       <parameter name="s=silence">
+                               <para>The number of seconds of silence that are permitted before the
+                               recording is terminated, regardless of the
+                               <replaceable>escape_digits</replaceable> or <replaceable>timeout</replaceable>
+                               arguments. If specified, this parameter must be preceded by
+                               <literal>s=</literal>.</para>
+                       </parameter>
                </syntax>
                <description>
                        <para>Record to a file until a given dtmf digit in the sequence is received.
@@ -392,11 +484,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        will be recorded. The <replaceable>timeout</replaceable> is the maximum record time in
                        milliseconds, or <literal>-1</literal> for no <replaceable>timeout</replaceable>.
                        <replaceable>offset samples</replaceable> is optional, and, if provided, will seek
-                       to the offset without exceeding the end of the file. <replaceable>silence</replaceable> is
+                       to the offset without exceeding the end of the
+                       file. <replaceable>beep</replaceable> can take any value, and causes Asterisk
+                       to play a beep to the channel that is about to be recorded. <replaceable>silence</replaceable> is
                        the number of seconds of silence allowed before the function returns despite the
                        lack of dtmf digits or reaching <replaceable>timeout</replaceable>. <replaceable>silence</replaceable>
                        value must be preceded by <literal>s=</literal> and is also optional.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="say alpha" language="en_US">
                <synopsis>
@@ -412,6 +509,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        without a digit being pressed, or the ASCII numerical value of the digit if one
                        was pressed or <literal>-1</literal> on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">say digits</ref>
+                       <ref type="agi">say number</ref>
+                       <ref type="agi">say phonetic</ref>
+                       <ref type="agi">say date</ref>
+                       <ref type="agi">say time</ref>
+                       <ref type="agi">say datetime</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="say digits" language="en_US">
                <synopsis>
@@ -427,6 +533,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        without a digit being pressed, or the ASCII numerical value of the digit if one
                        was pressed or <literal>-1</literal> on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">say alpha</ref>
+                       <ref type="agi">say number</ref>
+                       <ref type="agi">say phonetic</ref>
+                       <ref type="agi">say date</ref>
+                       <ref type="agi">say time</ref>
+                       <ref type="agi">say datetime</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="say number" language="en_US">
                <synopsis>
@@ -443,6 +558,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        completes without a digit being pressed, or the ASCII numerical value of
                        the digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">say alpha</ref>
+                       <ref type="agi">say digits</ref>
+                       <ref type="agi">say phonetic</ref>
+                       <ref type="agi">say date</ref>
+                       <ref type="agi">say time</ref>
+                       <ref type="agi">say datetime</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="say phonetic" language="en_US">
                <synopsis>
@@ -458,6 +582,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        playback completes without a digit pressed, the ASCII numerical value of the digit
                        if one was pressed, or <literal>-1</literal> on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">say alpha</ref>
+                       <ref type="agi">say digits</ref>
+                       <ref type="agi">say number</ref>
+                       <ref type="agi">say date</ref>
+                       <ref type="agi">say time</ref>
+                       <ref type="agi">say datetime</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="say date" language="en_US">
                <synopsis>
@@ -476,6 +609,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        completes without a digit being pressed, or the ASCII numerical value of the
                        digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">say alpha</ref>
+                       <ref type="agi">say digits</ref>
+                       <ref type="agi">say number</ref>
+                       <ref type="agi">say phonetic</ref>
+                       <ref type="agi">say time</ref>
+                       <ref type="agi">say datetime</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="say time" language="en_US">
                <synopsis>
@@ -494,6 +636,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        without a digit being pressed, or the ASCII numerical value of the digit if
                        one was pressed or <literal>-1</literal> on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">say alpha</ref>
+                       <ref type="agi">say digits</ref>
+                       <ref type="agi">say number</ref>
+                       <ref type="agi">say phonetic</ref>
+                       <ref type="agi">say date</ref>
+                       <ref type="agi">say datetime</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="say datetime" language="en_US">
                <synopsis>
@@ -521,6 +672,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        completes without a digit being pressed, or the ASCII numerical value of the
                        digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">say alpha</ref>
+                       <ref type="agi">say digits</ref>
+                       <ref type="agi">say number</ref>
+                       <ref type="agi">say phonetic</ref>
+                       <ref type="agi">say date</ref>
+                       <ref type="agi">say time</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="send image" language="en_US">
                <synopsis>
@@ -535,6 +695,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        the channel does not support image transmission.  Returns <literal>-1</literal>
                        only on error/hangup. Image names should not include extensions.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="send text" language="en_US">
                <synopsis>
@@ -552,6 +715,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        channel does not support text transmission. Returns <literal>-1</literal> only
                        on error/hangup.</para>
                </description>
+               <see-also>
+                       <ref type="agi">receive text</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="set autohangup" language="en_US">
                <synopsis>
@@ -565,6 +732,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        seconds in the future. Of course it can be hungup before then as well. Setting to
                        <literal>0</literal> will cause the autohangup feature to be disabled on this channel.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="set callerid" language="en_US">
                <synopsis>
@@ -576,6 +746,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Changes the callerid of the current channel.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="set context" language="en_US">
                <synopsis>
@@ -587,6 +760,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Sets the context for continuation upon exiting the application.</para>
                </description>
+               <see-also>
+                       <ref type="agi">set extension</ref>
+                       <ref type="agi">set priority</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="set extension" language="en_US">
                <synopsis>
@@ -598,6 +776,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Changes the extension for continuation upon exiting the application.</para>
                </description>
+               <see-also>
+                       <ref type="agi">set context</ref>
+                       <ref type="agi">set priority</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="set music" language="en_US">
                <synopsis>
@@ -622,6 +805,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        used. This generator will be stopped automatically when playing a file.</para>
                        <para>Always returns <literal>0</literal>.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="set priority" language="en_US">
                <synopsis>
@@ -634,6 +820,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Changes the priority for continuation upon exiting the application.
                        The priority must be a valid priority or label.</para>
                </description>
+               <see-also>
+                       <ref type="agi">set context</ref>
+                       <ref type="agi">set extension</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="set variable" language="en_US">
                <synopsis>
@@ -646,6 +837,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Sets a variable to the current channel.</para>
                </description>
+               <see-also>
+                       <ref type="agi">get variable</ref>
+                       <ref type="agi">get full variable</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="stream file" language="en_US">
                <synopsis>
@@ -683,6 +879,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </description>
                <see-also>
                        <ref type="agi">control stream file</ref>
+                       <ref type="agi">get option</ref>
+                       <ref type="application">AGI</ref>
                </see-also>
        </agi>
        <agi name="tdd mode" language="en_US">
@@ -701,6 +899,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Enable/Disable TDD transmission/reception on a channel. Returns <literal>1</literal> if
                        successful, or <literal>0</literal> if channel is not TDD-capable.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="verbose" language="en_US">
                <synopsis>
@@ -715,6 +916,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        message system. <replaceable>level</replaceable> is the verbose level (1-4).
                        Always returns <literal>1</literal></para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="wait for digit" language="en_US">
                <synopsis>
@@ -730,6 +934,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        one is received. Use <literal>-1</literal> for the <replaceable>timeout</replaceable> value if
                        you desire the call to block indefinitely.</para>
                </description>
+               <see-also>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="speech create" language="en_US">
                <synopsis>
@@ -741,6 +948,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Create a speech object to be used by the other Speech AGI commands.</para>
                </description>
+               <see-also>
+                       <ref type="agi">speech set</ref>
+                       <ref type="agi">speech destroy</ref>
+                       <ref type="agi">speech load grammar</ref>
+                       <ref type="agi">speech unload grammar</ref>
+                       <ref type="agi">speech activate grammar</ref>
+                       <ref type="agi">speech deactivate grammar</ref>
+                       <ref type="agi">speech recognize</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="speech set" language="en_US">
                <synopsis>
@@ -753,6 +970,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Set an engine-specific setting.</para>
                </description>
+               <see-also>
+                       <ref type="agi">speech create</ref>
+                       <ref type="agi">speech destroy</ref>
+                       <ref type="agi">speech load grammar</ref>
+                       <ref type="agi">speech unload grammar</ref>
+                       <ref type="agi">speech activate grammar</ref>
+                       <ref type="agi">speech deactivate grammar</ref>
+                       <ref type="agi">speech recognize</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="speech destroy" language="en_US">
                <synopsis>
@@ -765,6 +992,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </description>
                <see-also>
                        <ref type="agi">speech create</ref>
+                       <ref type="agi">speech set</ref>
+                       <ref type="agi">speech load grammar</ref>
+                       <ref type="agi">speech unload grammar</ref>
+                       <ref type="agi">speech activate grammar</ref>
+                       <ref type="agi">speech deactivate grammar</ref>
+                       <ref type="agi">speech recognize</ref>
+                       <ref type="application">AGI</ref>
                </see-also>
        </agi>
        <agi name="speech load grammar" language="en_US">
@@ -778,6 +1012,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Loads the specified grammar as the specified name.</para>
                </description>
+               <see-also>
+                       <ref type="agi">speech create</ref>
+                       <ref type="agi">speech set</ref>
+                       <ref type="agi">speech destroy</ref>
+                       <ref type="agi">speech unload grammar</ref>
+                       <ref type="agi">speech activate grammar</ref>
+                       <ref type="agi">speech deactivate grammar</ref>
+                       <ref type="agi">speech recognize</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="speech unload grammar" language="en_US">
                <synopsis>
@@ -789,6 +1033,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Unloads the specified grammar.</para>
                </description>
+               <see-also>
+                       <ref type="agi">speech create</ref>
+                       <ref type="agi">speech set</ref>
+                       <ref type="agi">speech destroy</ref>
+                       <ref type="agi">speech load grammar</ref>
+                       <ref type="agi">speech activate grammar</ref>
+                       <ref type="agi">speech deactivate grammar</ref>
+                       <ref type="agi">speech recognize</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="speech activate grammar" language="en_US">
                <synopsis>
@@ -800,6 +1054,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Activates the specified grammar on the speech object.</para>
                </description>
+               <see-also>
+                       <ref type="agi">speech create</ref>
+                       <ref type="agi">speech set</ref>
+                       <ref type="agi">speech destroy</ref>
+                       <ref type="agi">speech load grammar</ref>
+                       <ref type="agi">speech unload grammar</ref>
+                       <ref type="agi">speech deactivate grammar</ref>
+                       <ref type="agi">speech recognize</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="speech deactivate grammar" language="en_US">
                <synopsis>
@@ -811,6 +1075,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Deactivates the specified grammar on the speech object.</para>
                </description>
+               <see-also>
+                       <ref type="agi">speech create</ref>
+                       <ref type="agi">speech set</ref>
+                       <ref type="agi">speech destroy</ref>
+                       <ref type="agi">speech load grammar</ref>
+                       <ref type="agi">speech unload grammar</ref>
+                       <ref type="agi">speech activate grammar</ref>
+                       <ref type="agi">speech recognize</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <agi name="speech recognize" language="en_US">
                <synopsis>
@@ -825,14 +1099,27 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Plays back given <replaceable>prompt</replaceable> while listening for
                        speech and dtmf.</para>
                </description>
+               <see-also>
+                       <ref type="agi">speech create</ref>
+                       <ref type="agi">speech set</ref>
+                       <ref type="agi">speech destroy</ref>
+                       <ref type="agi">speech load grammar</ref>
+                       <ref type="agi">speech unload grammar</ref>
+                       <ref type="agi">speech activate grammar</ref>
+                       <ref type="agi">speech deactivate grammar</ref>
+                       <ref type="application">AGI</ref>
+               </see-also>
        </agi>
        <application name="AGI" language="en_US">
                <synopsis>
                        Executes an AGI compliant application.
                </synopsis>
                <syntax>
-                       <parameter name="command" required="true" />
+                       <parameter name="command" required="true">
+                               <para>How AGI should be invoked on the channel.</para>
+                       </parameter>
                        <parameter name="args">
+                               <para>Arguments to pass to the AGI script or server.</para>
                                <argument name="arg1" required="true" />
                                <argument name="arg2" multiple="yes" />
                        </parameter>
@@ -841,21 +1128,72 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Executes an Asterisk Gateway Interface compliant
                        program on a channel. AGI allows Asterisk to launch external programs written
                        in any language to control a telephony channel, play audio, read DTMF digits,
-                       etc. by communicating with the AGI protocol on <emphasis>stdin</emphasis> and
-                       <emphasis>stdout</emphasis>. As of <literal>1.6.0</literal>, this channel will
+                       etc. by communicating with the AGI protocol.</para>
+                       <para>The following variants of AGI exist, and are chosen based on the value
+                       passed to <replaceable>command</replaceable>:</para>
+                       <enumlist>
+                               <enum name="AGI">
+                                       <para>The classic variant of AGI, this will launch the script
+                                       specified by <replaceable>command</replaceable> as a new process.
+                                       Communication with the script occurs on <literal>stdin</literal> and
+                                       <literal>stdout</literal>. If the full path to the script is not
+                                       provided, the <directory>astagidir</directory> specified in
+                                       <filename>asterisk.conf</filename> will be used.
+                                       </para>
+                               </enum>
+                               <enum name="FastAGI">
+                                       <para>Connect Asterisk to a FastAGI server using a TCP connection.
+                                       The URI to the FastAGI server should be given in the form
+                                       <literal>[scheme]://host.domain[:port][/script/name]</literal>,
+                                       where <replaceable>scheme</replaceable> is either <literal>agi</literal>
+                                       or <literal>hagi</literal>.</para>
+                                       <para>In the case of <literal>hagi</literal>, an SRV lookup will be
+                                       performed to try to connect to a list of FastAGI servers. The hostname in
+                                       the URI must be prefixed with <literal>_agi._tcp</literal>. prior to the DNS resolution. For
+                                       example, if you specify the URI <literal>hagi://agi.example.com/foo.agi</literal>
+                                       the DNS query would be for <literal>_agi._tcp.agi.example.com</literal>. You
+                                       will need to make sure this resolves correctly.</para>
+                               </enum>
+                               <enum name="AsyncAGI">
+                                       <para>Use AMI to control the channel in AGI. AGI commands can be invoked
+                                       using the <literal>AMI</literal> action, with a variety of AGI specific
+                                       events passed back over the AMI connection. AsyncAGI should be invoked
+                                       by passing <literal>agi:async</literal> to the <replaceable>command</replaceable>
+                                       parameter.</para>
+                               </enum>
+                       </enumlist>
+                       <note>
+                       <para>As of <literal>1.6.0</literal>, this channel will
                        not stop dialplan execution on hangup inside of this application. Dialplan
                        execution will continue normally, even upon hangup until the AGI application
                        signals a desire to stop (either by exiting or, in the case of a net script, by
-                       closing the connection). A locally executed AGI script will receive SIGHUP on
-                       hangup from the channel except when using DeadAGI. A fast AGI server will
-                       correspondingly receive a HANGUP inline with the command dialog. Both of theses
-                       signals may be disabled by setting the <variable>AGISIGHUP</variable> channel
-                       variable to <literal>no</literal> before executing the AGI application.
+                       closing the connection).</para>
+                       <para>A locally executed AGI script will receive <literal>SIGHUP</literal> on
+                       hangup from the channel except when using <literal>DeadAGI</literal>
+                       (or when the channel is already hungup). A fast AGI server will
+                       correspondingly receive a <literal>HANGUP</literal> inline with the command dialog.
+                       Both of these signals may be disabled by setting the <variable>AGISIGHUP</variable>
+                       channel variable to <literal>no</literal> before executing the AGI application.
                        Alternatively, if you would like the AGI application to exit immediately
                        after a channel hangup is detected, set the <variable>AGIEXITONHANGUP</variable>
                        variable to <literal>yes</literal>.</para>
-                       <para>Use the CLI command <literal>agi show commands</literal> to list available agi
-                       commands.</para>
+                       </note>
+                       <example title="AGI invocation examples">
+                               ; Start the AGI script /tmp/my-cool-script.sh, passing it the contents
+                               ; of the channel variable FOO
+                               same => n,AGI(/tmp/my-cool-script.sh,${FOO})
+
+                               ; Start the AGI script my-cool-script.sh located in the astagidir
+                               ; directory, specified in asterisk.conf
+                               same => n,AGI(my-cool-script.sh)
+
+                               ; Connect to the FastAGI server located at 127.0.0.1 and start the script
+                               ; awesome-script
+                               same => n,AGI(agi://127.0.0.1/awesome-script)
+
+                               ; Start AsyncAGI
+                               same => n,AGI(agi:async)
+                       </example>
                        <para>This application sets the following channel variable upon completion:</para>
                        <variablelist>
                                <variable name="AGISTATUS">
@@ -869,8 +1207,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        </variablelist>
                </description>
                <see-also>
+                       <ref type="manager">AGI</ref>
+                       <ref type="managerEvent">AsyncAGIStart</ref>
+                       <ref type="managerEvent">AsyncAGIEnd</ref>
                        <ref type="application">EAGI</ref>
                        <ref type="application">DeadAGI</ref>
+                       <ref type="filename">asterisk.conf</ref>
                </see-also>
        </application>
        <application name="EAGI" language="en_US">
@@ -883,8 +1225,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </syntax>
                <description>
                        <para>Using 'EAGI' provides enhanced AGI, with incoming audio available out of band
-                       on file descriptor 3.</para>
-                       <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/para)" />
+                       on file descriptor 3. In all other respects, it behaves in the same fashion as
+                       AGI. See the documentation for the <literal>AGI</literal> dialplan application for
+                       more information on invoking AGI on a channel.</para>
+                       <para>This application sets the following channel variable upon completion:</para>
                        <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
                </description>
                <see-also>
@@ -901,7 +1245,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
                </syntax>
                <description>
-                       <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/para)" />
+                       <warning>
+                               <para>This application is deprecated and may be removed in a future version
+                               of Asterisk. Use the replacement application <literal>AGI</literal> instead
+                               of <literal>DeadAGI</literal>.
+                               </para>
+                       </warning>
+                       <para>Execute AGI on a 'dead' or hungup channel. See the documentation for the
+                       <literal>AGI</literal> dialplan application for more information on invoking
+                       AGI on a channel.</para>
+                       <para>This application sets the following channel variable upon completion:</para>
                        <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
                </description>
                <see-also>
@@ -929,31 +1282,48 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Add an AGI command to the execute queue of the channel in Async AGI.</para>
                </description>
+               <see-also>
+                       <ref type="managerEvent">AsyncAGIStart</ref>
+                       <ref type="managerEvent">AsyncAGIExec</ref>
+                       <ref type="managerEvent">AsyncAGIEnd</ref>
+               </see-also>
        </manager>
        <managerEvent language="en_US" name="AsyncAGIStart">
                <managerEventInstance class="EVENT_FLAG_AGI">
                        <synopsis>Raised when a channel starts AsyncAGI command processing.</synopsis>
                        <syntax>
-                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <channel_snapshot/>
                                <parameter name="Env">
                                        <para>URL encoded string read from the AsyncAGI server.</para>
                                </parameter>
                        </syntax>
+                       <see-also>
+                               <ref type="managerEvent">AsyncAGIEnd</ref>
+                               <ref type="managerEvent">AsyncAGIExec</ref>
+                               <ref type="application">AGI</ref>
+                               <ref type="manager">AGI</ref>
+                       </see-also>
                </managerEventInstance>
        </managerEvent>
        <managerEvent language="en_US" name="AsyncAGIEnd">
                <managerEventInstance class="EVENT_FLAG_AGI">
                        <synopsis>Raised when a channel stops AsyncAGI command processing.</synopsis>
                        <syntax>
-                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <channel_snapshot/>
                        </syntax>
+                       <see-also>
+                               <ref type="managerEvent">AsyncAGIStart</ref>
+                               <ref type="managerEvent">AsyncAGIExec</ref>
+                               <ref type="application">AGI</ref>
+                               <ref type="manager">AGI</ref>
+                       </see-also>
                </managerEventInstance>
        </managerEvent>
        <managerEvent language="en_US" name="AsyncAGIExec">
                <managerEventInstance class="EVENT_FLAG_AGI">
                        <synopsis>Raised when AsyncAGI completes an AGI command.</synopsis>
                        <syntax>
-                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <channel_snapshot/>
                                <parameter name="CommandID" required="false">
                                        <para>Optional command ID sent by the AsyncAGI server to identify the command.</para>
                                </parameter>
@@ -961,13 +1331,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <para>URL encoded result string from the executed AGI command.</para>
                                </parameter>
                        </syntax>
+                       <see-also>
+                               <ref type="managerEvent">AsyncAGIStart</ref>
+                               <ref type="managerEvent">AsyncAGIEnd</ref>
+                               <ref type="application">AGI</ref>
+                               <ref type="manager">AGI</ref>
+                       </see-also>
                </managerEventInstance>
        </managerEvent>
        <managerEvent language="en_US" name="AGIExecStart">
                <managerEventInstance class="EVENT_FLAG_AGI">
                        <synopsis>Raised when a received AGI command starts processing.</synopsis>
                        <syntax>
-                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <channel_snapshot/>
                                <parameter name="Command">
                                        <para>The AGI command as received from the external source.</para>
                                </parameter>
@@ -975,13 +1351,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <para>Random identification number assigned to the execution of this command.</para>
                                </parameter>
                        </syntax>
+                       <see-also>
+                               <ref type="managerEvent">AGIExecEnd</ref>
+                               <ref type="application">AGI</ref>
+                       </see-also>
                </managerEventInstance>
        </managerEvent>
        <managerEvent language="en_US" name="AGIExecEnd">
                <managerEventInstance class="EVENT_FLAG_AGI">
                        <synopsis>Raised when a received AGI command completes processing.</synopsis>
                        <syntax>
-                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <channel_snapshot/>
                                <xi:include xpointer="xpointer(/docs/managerEvent[@name='AGIExecStart']/managerEventInstance/syntax/parameter)" />
                                <parameter name="ResultCode">
                                        <para>The numeric result code from AGI</para>
@@ -990,6 +1370,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <para>The text result reason from AGI</para>
                                </parameter>
                        </syntax>
+                       <see-also>
+                               <ref type="managerEvent">AGIExecStart</ref>
+                               <ref type="application">AGI</ref>
+                       </see-also>
                </managerEventInstance>
        </managerEvent>
  ***/
@@ -1027,44 +1411,66 @@ enum agi_result {
        AGI_RESULT_HANGUP,
 };
 
-struct stasis_message_type *agi_exec_start_type(void);
-struct stasis_message_type *agi_exec_end_type(void);
-struct stasis_message_type *agi_async_start_type(void);
-struct stasis_message_type *agi_async_exec_type(void);
-struct stasis_message_type *agi_async_end_type(void);
-
-STASIS_MESSAGE_TYPE_DEFN(agi_exec_start_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_exec_end_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_start_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_exec_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_end_type);
-
-static void agi_channel_manager_event(void *data,
-       struct stasis_subscription *sub, struct stasis_topic *topic,
-       struct stasis_message *message)
+static struct ast_manager_event_blob *agi_channel_to_ami(const char *type, struct stasis_message *message)
 {
-       const char *type = data;
        struct ast_channel_blob *obj = stasis_message_data(message);
-       RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+       RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
        RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
 
-       channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
-       if (!channel_event_string) {
-               return;
-       }
-
+       channel_string = ast_manager_build_channel_state_string(obj->snapshot);
        event_string = ast_manager_str_from_json_object(obj->blob, NULL);
-       if (!event_string) {
-               return;
+       if (!channel_string || !event_string) {
+               return NULL;
        }
 
-       manager_event(EVENT_FLAG_AGI, type,
+       return ast_manager_event_blob_create(EVENT_FLAG_AGI, type,
                "%s"
                "%s",
-               ast_str_buffer(channel_event_string),
+               ast_str_buffer(channel_string),
                ast_str_buffer(event_string));
 }
 
+static struct ast_manager_event_blob *agi_exec_start_to_ami(struct stasis_message *message)
+{
+       return agi_channel_to_ami("AGIExecStart", message);
+}
+
+static struct ast_manager_event_blob *agi_exec_end_to_ami(struct stasis_message *message)
+{
+       return agi_channel_to_ami("AGIExecEnd", message);
+}
+
+static struct ast_manager_event_blob *agi_async_start_to_ami(struct stasis_message *message)
+{
+       return agi_channel_to_ami("AsyncAGIStart", message);
+}
+
+static struct ast_manager_event_blob *agi_async_exec_to_ami(struct stasis_message *message)
+{
+       return agi_channel_to_ami("AsyncAGIExec", message);
+}
+
+static struct ast_manager_event_blob *agi_async_end_to_ami(struct stasis_message *message)
+{
+       return agi_channel_to_ami("AsyncAGIEnd", message);
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_start_type,
+       .to_ami = agi_exec_start_to_ami,
+       );
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_end_type,
+       .to_ami = agi_exec_end_to_ami,
+       );
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_start_type,
+       .to_ami = agi_async_start_to_ami,
+       );
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_exec_type,
+       .to_ami = agi_async_exec_to_ami,
+       );
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_end_type,
+       .to_ami = agi_async_end_to_ami,
+       );
+
 static agi_command *find_command(const char * const cmds[], int exact);
 
 AST_THREADSTORAGE(agi_buf);
@@ -1453,9 +1859,11 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char
           to execute based on the setup info */
        ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
        startblob = ast_json_pack("{s: s}", "Env", ami_buffer);
-       ast_channel_publish_blob(chan, agi_async_start_type(), startblob);
 
-       hungup = ast_check_hangup(chan);
+       ast_channel_publish_cached_blob(chan, agi_async_start_type(), startblob);
+
+       hungup = ast_check_hangup_locked(chan);
+
        for (;;) {
                /*
                 * Process as many commands as we can.  Commands are added via
@@ -1499,7 +1907,7 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char
                        if (execblob && !ast_strlen_zero(cmd->cmd_id)) {
                                ast_json_object_set(execblob, "CommandId", ast_json_string_create(cmd->cmd_id));
                        }
-                       ast_channel_publish_blob(chan, agi_async_exec_type(), execblob);
+                       ast_channel_publish_cached_blob(chan, agi_async_exec_type(), execblob);
 
                        free_agi_cmd(cmd);
 
@@ -1559,7 +1967,7 @@ async_agi_done:
                ast_speech_destroy(async_agi.speech);
        }
        /* notify manager users this channel cannot be controlled anymore by Async AGI */
-       ast_channel_publish_blob(chan, agi_async_end_type(), NULL);
+       ast_channel_publish_cached_blob(chan, agi_async_end_type(), NULL);
 
 async_agi_abort:
        /* close the pipe */
@@ -2098,7 +2506,7 @@ static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc
        long offsetms = 0;
        char offsetbuf[20];
 
-       if (argc < 5 || argc > 9) {
+       if (argc < 5 || argc > 10) {
                return RESULT_SHOWUSAGE;
        }
 
@@ -2122,7 +2530,11 @@ static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc
                suspend = argv[8];
        }
 
-       res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
+       if (argc > 9 && (sscanf(argv[9], "%30ld", &offsetms) != 1)) {
+               return RESULT_SHOWUSAGE;
+       }
+
+       res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, &offsetms);
 
        /* If we stopped on one of our stop keys, return 0  */
        if (res > 0 && stop && strchr(stop, res)) {
@@ -2143,7 +2555,7 @@ static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc
        snprintf(offsetbuf, sizeof(offsetbuf), "%ld", offsetms);
        pbx_builtin_setvar_helper(chan, "CPLAYBACKOFFSET", offsetbuf);
 
-       ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
+       ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, offsetms);
 
        return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
 }
@@ -2168,15 +2580,16 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const
        }
 
        if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
-               ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
-               return RESULT_SUCCESS;
+               ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
+               return RESULT_FAILURE;
        }
 
        if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan)))) {
                ast_debug(1, "Ooh, found a video stream, too\n");
        }
-
-       ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
+       ast_verb(3, "<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
+               ast_channel_name(chan), argv[2], ast_format_get_name(ast_channel_writeformat(chan)),
+               edigits, sample_offset, S_OR(ast_channel_language(chan), "default"));
 
        ast_seekstream(fs, 0, SEEK_END);
        max_length = ast_tellstream(fs);
@@ -2228,9 +2641,9 @@ static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const
        }
 
        if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
-               ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
+               ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
                ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
-               return RESULT_SUCCESS;
+               return RESULT_FAILURE;
        }
 
        if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan))))
@@ -2309,11 +2722,37 @@ static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const
 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
        int res;
+       int sensitivity = AST_SAY_CASE_NONE;
 
-       if (argc != 4)
+       if (argc < 4 || argc > 5) {
                return RESULT_SHOWUSAGE;
+       }
 
-       res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
+       if (argc > 4) {
+               switch (argv[4][0]) {
+               case 'a':
+               case 'A':
+                       sensitivity = AST_SAY_CASE_ALL;
+                       break;
+               case 'l':
+               case 'L':
+                       sensitivity = AST_SAY_CASE_LOWER;
+                       break;
+               case 'n':
+               case 'N':
+                       sensitivity = AST_SAY_CASE_NONE;
+                       break;
+               case 'u':
+               case 'U':
+                       sensitivity = AST_SAY_CASE_UPPER;
+                       break;
+               case '\0':
+                       break;
+               default:
+                       return RESULT_SHOWUSAGE;
+               }
+       }
+       res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->audio, agi->ctrl);
        if (res == 1) /* New command */
                return RESULT_SUCCESS;
        ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
@@ -2478,8 +2917,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
        int silence = 0;                /* amount of silence to allow */
        int gotsilence = 0;             /* did we timeout for silence? */
        char *silencestr = NULL;
-       struct ast_format rfmt;
-       ast_format_clear(&rfmt);
+       RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
 
        /* XXX EAGI FIXME XXX */
 
@@ -2509,8 +2947,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
        }
 
        if (silence > 0) {
-               ast_format_copy(&rfmt, ast_channel_readformat(chan));
-               res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
+               rfmt = ao2_bump(ast_channel_readformat(chan));
+               res = ast_set_read_format(chan, ast_format_slin);
                if (res < 0) {
                        ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
                        ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
@@ -2524,7 +2962,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
                }
                ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
        }
-       
+
        /* backward compatibility, if no offset given, arg[6] would have been
         * caught below and taken to be a beep, else if it is a digit then it is a
         * offset */
@@ -2569,8 +3007,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
                        }
                        f = ast_read(chan);
                        if (!f) {
-                               ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
                                ast_closestream(fs);
+                               ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
                                if (sildet)
                                        ast_dsp_free(sildet);
                                return RESULT_FAILURE;
@@ -2584,8 +3022,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
                                        ast_stream_rewind(fs, 200);
                                        ast_truncstream(fs);
                                        sample_offset = ast_tellstream(fs);
-                                       ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
                                        ast_closestream(fs);
+                                       ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
                                        ast_frfree(f);
                                        if (sildet)
                                                ast_dsp_free(sildet);
@@ -2629,12 +3067,12 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
                        ast_truncstream(fs);
                        sample_offset = ast_tellstream(fs);
                }
-               ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
                ast_closestream(fs);
+               ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
        }
 
        if (silence > 0) {
-               res = ast_set_read_format(chan, &rfmt);
+               res = ast_set_read_format(chan, rfmt);
                if (res)
                        ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
                ast_dsp_free(sildet);
@@ -2658,7 +3096,9 @@ static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const
                whentohangup.tv_sec = timeout;
                whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
        }
+       ast_channel_lock(chan);
        ast_channel_setwhentohangup_tv(chan, whentohangup);
+       ast_channel_unlock(chan);
        ast_agi_send(agi->fd, chan, "200 result=0\n");
        return RESULT_SUCCESS;
 }
@@ -2702,29 +3142,14 @@ static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char
        ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
 
        if ((app_to_exec = pbx_findapp(argv[1]))) {
+               ast_channel_lock(chan);
                if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) {
                        ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS);
                }
-               if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
-                       char *compat = ast_alloca(strlen(argv[2]) * 2 + 1), *cptr;
-                       const char *vptr;
-                       for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
-                               if (*vptr == ',') {
-                                       *cptr++ = '\\';
-                                       *cptr++ = ',';
-                               } else if (*vptr == '|') {
-                                       *cptr++ = ',';
-                               } else {
-                                       *cptr++ = *vptr;
-                               }
-                       }
-                       *cptr = '\0';
-                       res = pbx_exec(chan, app_to_exec, compat);
-               } else {
-                       res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
-               }
+               ast_channel_unlock(chan);
+               res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
                if (!workaround) {
-                       ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS);
+                       ast_channel_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
                }
        } else {
                ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
@@ -2759,16 +3184,18 @@ static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, cons
 
 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
-       struct ast_channel *c;
        if (argc == 2) {
                /* no argument: supply info on the current channel */
-               ast_agi_send(agi->fd, chan, "200 result=%d\n", ast_channel_state(chan));
+               ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));
                return RESULT_SUCCESS;
        } else if (argc == 3) {
+               RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
                /* one argument: look for info on the specified channel */
-               if ((c = ast_channel_get_by_name(argv[2]))) {
-                       ast_agi_send(agi->fd, chan, "200 result=%d\n", ast_channel_state(c));
-                       c = ast_channel_unref(c);
+               if ((msg = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(), argv[2]))) {
+                       struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
+
+                       ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);
                        return RESULT_SUCCESS;
                }
                /* if we get this far no channel name matched the argument given */
@@ -2781,6 +3208,10 @@ static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, co
 
 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
+       if (argc != 4) {
+               return RESULT_SHOWUSAGE;
+       }
+
        if (argv[3])
                pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
 
@@ -2885,7 +3316,7 @@ static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char
                        break;
                }
        } while (1);
-       
+
        if (res)
                ast_agi_send(agi->fd, chan, "200 result=0\n");
        else
@@ -2985,7 +3416,6 @@ static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const c
 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
        struct ast_format_cap *cap;
-       struct ast_format tmpfmt;
 
        /* If a structure already exists, return an error */
        if (agi->speech) {
@@ -2993,16 +3423,16 @@ static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, con
                return RESULT_SUCCESS;
        }
 
-       if (!(cap = ast_format_cap_alloc_nolock())) {
+       if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
                return RESULT_FAILURE;
        }
-       ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+       ast_format_cap_append(cap, ast_format_slin, 0);
        if ((agi->speech = ast_speech_new(argv[2], cap))) {
                ast_agi_send(agi->fd, chan, "200 result=1\n");
        } else {
                ast_agi_send(agi->fd, chan, "200 result=0\n");
        }
-       cap = ast_format_cap_destroy(cap);
+       ao2_ref(cap, -1);
 
        return RESULT_SUCCESS;
 }
@@ -3135,7 +3565,6 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
        const char *prompt;
        char dtmf = 0, tmp[4096] = "", *buf = tmp;
        int timeout = 0, offset = 0, res = 0, i = 0;
-       struct ast_format old_read_format;
        long current_offset = 0;
        const char *reason = NULL;
        struct ast_frame *fr = NULL;
@@ -3159,8 +3588,7 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
                offset = atoi(argv[4]);
 
        /* We want frames coming in signed linear */
-       ast_format_copy(&old_read_format, ast_channel_readformat(chan));
-       if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
+       if (ast_set_read_format(chan, ast_format_slin)) {
                ast_agi_send(agi->fd, chan, "200 result=0\n");
                return RESULT_SUCCESS;
        }
@@ -3298,15 +3726,15 @@ static struct agi_command commands[] = {
        { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
        { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
        { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
-       { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 }, 
+       { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 },
        { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
        { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
        { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
-       { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0}, 
-       { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0}, 
-       { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0}, 
+       { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
+       { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0},
+       { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0},
        { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
-       { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0}, 
+       { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0},
        { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
        { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
        { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
@@ -3436,10 +3864,9 @@ int AST_OPTIONAL_API_NAME(ast_agi_unregister)(struct ast_module *mod, agi_comman
        }
        AST_RWLIST_TRAVERSE_SAFE_END;
        AST_RWLIST_UNLOCK(&agi_commands);
-       if (unregistered)
+       if (unregistered) {
                ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
-       else
-               ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
+       }
        return unregistered;
 }
 
@@ -3598,12 +4025,12 @@ static void publish_async_exec_end(struct ast_channel *chan, int command_id, con
                             "Command", command,
                             "ResultCode", result_code,
                             "Result", result);
-       ast_channel_publish_blob(chan, agi_exec_end_type(), blob);
+       ast_channel_publish_cached_blob(chan, agi_exec_end_type(), blob);
 }
 
 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
 {
-       const char *argv[MAX_ARGS];
+       const char *argv[MAX_ARGS] = {0};
        int argc = MAX_ARGS;
        int res;
        agi_command *c;
@@ -3616,7 +4043,7 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
        startblob = ast_json_pack("{s: i, s: s}",
                             "CommandId", command_id,
                             "Command", ami_cmd);
-       ast_channel_publish_blob(chan, agi_exec_start_type(), startblob);
+       ast_channel_publish_cached_blob(chan, agi_exec_start_type(), startblob);
 
        parse_args(buf, &argc, argv);
        c = find_command(argv, 0);
@@ -3625,11 +4052,6 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
                the module we are using */
                if (c->mod != ast_module_info->self)
                        ast_module_ref(c->mod);
-               /* If the AGI command being executed is an actual application (using agi exec)
-               the app field will be updated in pbx_exec via handle_exec */
-               if (ast_channel_cdr(chan) && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
-                       ast_cdr_setapp(ast_channel_cdr(chan), "AGI", buf);
-
                res = c->handler(chan, agi, argc, argv);
                if (c->mod != ast_module_info->self)
                        ast_module_unref(c->mod);
@@ -3644,7 +4066,7 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
                                ast_agi_send(agi->fd, chan, "520 Invalid command syntax.  Proper usage not available.\n");
                        } else {
                                ast_agi_send(agi->fd, chan, "520-Invalid command syntax.  Proper usage follows:\n");
-                               ast_agi_send(agi->fd, chan, "%s", c->usage);
+                               ast_agi_send(agi->fd, chan, "%s\n", c->usage);
                                ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
                        }
 
@@ -3680,7 +4102,7 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
                        break;
                }
        } else if (c) {
-               ami_res = "Command Not Permitted on a dead channel";
+               ami_res = "Command Not Permitted on a dead channel or intercept routine";
                resultcode = 511;
 
                ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
@@ -3697,6 +4119,7 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
 
        return AGI_RESULT_SUCCESS;
 }
+
 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
 {
        struct ast_channel *c;
@@ -3715,7 +4138,9 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
        const char *sighup_str;
        const char *exit_on_hangup_str;
        int exit_on_hangup;
-       
+       /*! Running in an interception routine is like DeadAGI mode.  No touchy the channel frames. */
+       int in_intercept = ast_channel_get_intercept_mode();
+
        ast_channel_lock(chan);
        sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
        send_sighup = !ast_false(sighup_str);
@@ -3730,7 +4155,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
                close(agi->ctrl);
                return AGI_RESULT_FAILURE;
        }
-       
+
        setlinebuf(readf);
        setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
        for (;;) {
@@ -3749,7 +4174,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
                        }
                }
                ms = -1;
-               if (dead) {
+               if (dead || in_intercept) {
                        c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
                } else if (!ast_check_hangup(chan)) {
                        c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
@@ -3827,10 +4252,10 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
 
                        if (agidebug)
                                ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf);
-                       cmd_status = agi_handle_command(chan, agi, buf, dead);
+                       cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept);
                        switch (cmd_status) {
                        case AGI_RESULT_FAILURE:
-                               if (dead || !ast_check_hangup(chan)) {
+                               if (dead || in_intercept || !ast_check_hangup(chan)) {
                                        /* The failure was not because of a hangup. */
                                        returnstatus = AGI_RESULT_FAILURE;
                                }
@@ -3846,6 +4271,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
                        }
                }
        }
+
        if (agi->speech) {
                ast_speech_destroy(agi->speech);
        }
@@ -4015,9 +4441,6 @@ static int write_htmldump(const char *filename)
 
        AST_RWLIST_RDLOCK(&agi_commands);
        AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
-#ifdef AST_XML_DOCS
-               char *stringptmp;
-#endif
                char *tempstr, *stringp;
 
                if (!command->cmda[0])  /* end ? */
@@ -4030,8 +4453,7 @@ static int write_htmldump(const char *filename)
                fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
                fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
 #ifdef AST_XML_DOCS
-               stringptmp = ast_xmldoc_printable(command->usage, 0);
-               stringp = ast_strdup(stringptmp);
+               stringp = ast_xmldoc_printable(command->usage, 0);
 #else
                stringp = ast_strdup(command->usage);
 #endif
@@ -4049,9 +4471,6 @@ static int write_htmldump(const char *filename)
                fprintf(htmlfile, "</TD></TR>\n");
                fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
                ast_free(stringp);
-#ifdef AST_XML_DOCS
-               ast_free(stringptmp);
-#endif
        }
        AST_RWLIST_UNLOCK(&agi_commands);
        fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
@@ -4161,23 +4580,42 @@ static int agi_exec(struct ast_channel *chan, const char *data)
 static int eagi_exec(struct ast_channel *chan, const char *data)
 {
        int res;
-       struct ast_format readformat;
+       struct ast_format *readformat;
+       struct ast_format *requested_format = NULL;
+       const char *requested_format_name;
 
        if (ast_check_hangup(chan)) {
                ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
                return 0;
        }
-       ast_format_copy(&readformat, ast_channel_readformat(chan));
-       if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
+
+       requested_format_name = pbx_builtin_getvar_helper(chan, "EAGI_AUDIO_FORMAT");
+       if (requested_format_name) {
+               requested_format = ast_format_cache_get(requested_format_name);
+               if (requested_format) {
+                       ast_verb(3, "<%s> Setting EAGI audio pipe format to %s\n",
+                                        ast_channel_name(chan), ast_format_get_name(requested_format));
+               } else {
+                       ast_log(LOG_ERROR, "Could not find requested format: %s\n", requested_format_name);
+               }
+       }
+
+       readformat = ao2_bump(ast_channel_readformat(chan));
+       if (ast_set_read_format(chan, requested_format ?: ast_format_slin)) {
                ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan));
+               ao2_cleanup(requested_format);
+               ao2_cleanup(readformat);
                return -1;
        }
        res = agi_exec_full(chan, data, 1, 0);
        if (!res) {
-               if (ast_set_read_format(chan, &readformat)) {
-                       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan), ast_getformatname(&readformat));
+               if (ast_set_read_format(chan, readformat)) {
+                       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan),
+                               ast_format_get_name(readformat));
                }
        }
+       ao2_cleanup(requested_format);
+       ao2_cleanup(readformat);
        return res;
 }
 
@@ -4236,17 +4674,6 @@ AST_TEST_DEFINE(test_agi_null_docs)
 
 static int unload_module(void)
 {
-       struct stasis_message_router *message_router;
-
-       message_router = ast_manager_get_message_router();
-       if (message_router) {
-               stasis_message_router_remove(message_router, agi_exec_start_type());
-               stasis_message_router_remove(message_router, agi_exec_end_type());
-               stasis_message_router_remove(message_router, agi_async_start_type());
-               stasis_message_router_remove(message_router, agi_async_exec_type());
-               stasis_message_router_remove(message_router, agi_async_end_type());
-       }
-
        STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_start_type);
        STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_end_type);
        STASIS_MESSAGE_TYPE_CLEANUP(agi_async_start_type);
@@ -4254,71 +4681,44 @@ static int unload_module(void)
        STASIS_MESSAGE_TYPE_CLEANUP(agi_async_end_type);
 
        ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
-       /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
-          we know that these commands were registered by this module and are still registered
-       */
-       (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
+       ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
        ast_unregister_application(eapp);
        ast_unregister_application(deadapp);
        ast_manager_unregister("AGI");
+       ast_unregister_application(app);
        AST_TEST_UNREGISTER(test_agi_null_docs);
-       return ast_unregister_application(app);
+       return 0;
 }
 
 static int load_module(void)
 {
-       struct stasis_message_router *message_router;
+       int err = 0;
 
-       message_router = ast_manager_get_message_router();
-       if (!message_router) {
-               return AST_MODULE_LOAD_DECLINE;
-       }
+       err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_start_type);
+       err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_end_type);
+       err |= STASIS_MESSAGE_TYPE_INIT(agi_async_start_type);
+       err |= STASIS_MESSAGE_TYPE_INIT(agi_async_exec_type);
+       err |= STASIS_MESSAGE_TYPE_INIT(agi_async_end_type);
+
+       err |= ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
+       err |= ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
+       err |= ast_register_application_xml(deadapp, deadagi_exec);
+       err |= ast_register_application_xml(eapp, eagi_exec);
+       err |= ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
+       err |= ast_register_application_xml(app, agi_exec);
 
-       STASIS_MESSAGE_TYPE_INIT(agi_exec_start_type);
-       STASIS_MESSAGE_TYPE_INIT(agi_exec_end_type);
-       STASIS_MESSAGE_TYPE_INIT(agi_async_start_type);
-       STASIS_MESSAGE_TYPE_INIT(agi_async_exec_type);
-       STASIS_MESSAGE_TYPE_INIT(agi_async_end_type);
-
-       stasis_message_router_add(message_router,
-                                 agi_exec_start_type(),
-                                 agi_channel_manager_event,
-                                 "AGIExecStart");
-
-       stasis_message_router_add(message_router,
-                                 agi_exec_end_type(),
-                                 agi_channel_manager_event,
-                                 "AGIExecEnd");
-
-       stasis_message_router_add(message_router,
-                                 agi_async_start_type(),
-                                 agi_channel_manager_event,
-                                 "AsyncAGIStart");
-
-       stasis_message_router_add(message_router,
-                                 agi_async_exec_type(),
-                                 agi_channel_manager_event,
-                                 "AsyncAGIExec");
-
-       stasis_message_router_add(message_router,
-                                 agi_async_end_type(),
-                                 agi_channel_manager_event,
-                                 "AsyncAGIEnd");
-
-       ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
-       /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
-          no other commands have been registered yet
-       */
-       (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
-       ast_register_application_xml(deadapp, deadagi_exec);
-       ast_register_application_xml(eapp, eagi_exec);
-       ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
        AST_TEST_REGISTER(test_agi_null_docs);
-       return ast_register_application_xml(app, agi_exec);
+
+       if (err) {
+               unload_module();
+               return AST_MODULE_LOAD_DECLINE;
+       }
+       return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk Gateway Interface (AGI)",
-               .load = load_module,
-               .unload = unload_module,
-               .load_pri = AST_MODPRI_APP_DEPEND,
-               );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_APP_DEPEND,
+);