loader: Add dependency fields to module structures.
[asterisk/asterisk.git] / res / res_agi.c
index 25251f3..2d0dc27 100644 (file)
  *
  * \author Mark Spencer <markster@digium.com>
  *
- * \todo Convert the rest of the AGI commands over to XML documentation
  */
 
 /*** MODULEINFO
+       <depend>res_speech</depend>
        <support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include <math.h>
 #include <signal.h>
 #include <sys/time.h>
@@ -68,6 +66,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 +83,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 +97,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 +138,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,10 +153,10 @@ 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">
@@ -187,6 +191,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>
@@ -202,6 +211,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>
@@ -216,6 +231,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>
@@ -233,6 +254,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>
@@ -249,6 +276,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>
@@ -264,6 +297,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>
@@ -278,6 +314,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>
@@ -294,6 +333,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>
@@ -309,6 +353,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">
@@ -324,6 +370,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>
@@ -336,6 +387,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>
@@ -345,6 +399,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>
@@ -362,6 +419,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>
@@ -378,19 +439,45 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        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>
                </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.
@@ -398,11 +485,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>
@@ -418,6 +510,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>
@@ -433,6 +534,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>
@@ -449,6 +559,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>
@@ -464,6 +583,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>
@@ -482,6 +610,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>
@@ -500,6 +637,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>
@@ -527,6 +673,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>
@@ -541,6 +696,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>
@@ -558,6 +716,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>
@@ -571,6 +733,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>
@@ -582,6 +747,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>
@@ -593,6 +761,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>
@@ -604,6 +777,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>
@@ -628,6 +806,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>
@@ -640,6 +821,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>
@@ -652,6 +838,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>
@@ -689,6 +880,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">
@@ -707,6 +900,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>
@@ -721,6 +917,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>
@@ -736,6 +935,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>
@@ -747,6 +949,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>
@@ -759,6 +971,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>
@@ -771,6 +993,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">
@@ -784,6 +1013,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>
@@ -795,6 +1034,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>
@@ -806,6 +1055,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>
@@ -817,6 +1076,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>
@@ -831,14 +1100,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>
@@ -847,21 +1129,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">
@@ -875,8 +1208,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">
@@ -889,8 +1226,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>
@@ -907,7 +1246,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>
@@ -935,6 +1283,11 @@ 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">
@@ -945,6 +1298,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <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">
@@ -953,6 +1312,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <syntax>
                                <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">
@@ -967,6 +1332,12 @@ 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">
@@ -981,6 +1352,10 @@ 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">
@@ -996,6 +1371,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>
  ***/
@@ -1033,38 +1412,66 @@ enum agi_result {
        AGI_RESULT_HANGUP,
 };
 
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_start_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_end_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_start_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_exec_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(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 +1860,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 +1908,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 +1968,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 */
@@ -1637,7 +2046,7 @@ static int handle_connection(const char *agiurl, const struct ast_sockaddr addr,
        FastAGI defaults to port 4573 */
 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
 {
-       int s = 0, flags;
+       int s = 0;
        char *host, *script;
        int num_addrs = 0, i = 0;
        struct ast_sockaddr *addrs;
@@ -1667,14 +2076,7 @@ static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
                        continue;
                }
 
-               if ((flags = fcntl(s, F_GETFL)) < 0) {
-                       ast_log(LOG_WARNING, "fcntl(F_GETFL) failed: %s\n", strerror(errno));
-                       close(s);
-                       continue;
-               }
-
-               if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
-                       ast_log(LOG_WARNING, "fnctl(F_SETFL) failed: %s\n", strerror(errno));
+               if (ast_fd_set_flags(s, O_NONBLOCK)) {
                        close(s);
                        continue;
                }
@@ -1840,9 +2242,8 @@ static enum agi_result launch_script(struct ast_channel *chan, char *script, int
                        close(toast[1]);
                        return AGI_RESULT_FAILURE;
                }
-               res = fcntl(audio[1], F_GETFL);
-               if (res > -1)
-                       res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
+
+               res = ast_fd_set_flags(audio[1], O_NONBLOCK);
                if (res < 0) {
                        ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
                        close(fromast[0]);
@@ -1985,7 +2386,7 @@ static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, con
                return RESULT_SHOWUSAGE;
        if (sscanf(argv[3], "%30d", &to) != 1)
                return RESULT_SHOWUSAGE;
-       res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
+       res = ast_waitfordigit_full(chan, to, NULL, agi->audio, agi->ctrl);
        ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
        return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
 }
@@ -2179,8 +2580,9 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const
        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);
@@ -2264,7 +2666,7 @@ static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const
 
        /* If the user didnt press a key, wait for digitTimeout*/
        if (res == 0 ) {
-               res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
+               res = ast_waitfordigit_full(chan, timeout, NULL, agi->audio, agi->ctrl);
                /* Make sure the new result is in the escape digits of the GET OPTION */
                if ( !strchr(edigits,res) )
                        res=0;
@@ -2508,8 +2910,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 */
 
@@ -2539,8 +2940,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);
@@ -2599,8 +3000,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;
@@ -2614,8 +3015,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);
@@ -2659,12 +3060,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);
@@ -2688,7 +3089,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;
 }
@@ -2732,29 +3135,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]);
@@ -2791,7 +3179,7 @@ static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, co
 {
        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);
@@ -2800,7 +3188,7 @@ static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, co
                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=%d\n", snapshot->state);
+                       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 */
@@ -2813,6 +3201,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]);
 
@@ -3017,7 +3409,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) {
@@ -3025,16 +3416,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;
 }
@@ -3167,7 +3558,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;
@@ -3191,8 +3581,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;
        }
@@ -3468,10 +3857,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;
 }
 
@@ -3630,12 +4018,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;
@@ -3648,18 +4036,23 @@ 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);
-       if (c && (!dead || (dead && c->dead))) {
-               /* if this command wasn't registered by res_agi, be sure to usecount
-               the module we are using */
-               if (c->mod != ast_module_info->self)
-                       ast_module_ref(c->mod);
+       if (!c || !ast_module_running_ref(c->mod)) {
+               ami_res = "Invalid or unknown command";
+               resultcode = 510;
+
+               ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
+
+               publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
+
+               return AGI_RESULT_SUCCESS;
+       }
+
+       if (!dead || (dead && c->dead)) {
                res = c->handler(chan, agi, argc, argv);
-               if (c->mod != ast_module_info->self)
-                       ast_module_unref(c->mod);
                switch (res) {
                case RESULT_SHOWUSAGE:
                        ami_res = "Usage";
@@ -3671,7 +4064,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");
                        }
 
@@ -3706,24 +4099,19 @@ 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";
-               resultcode = 511;
-
-               ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
-
-               publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
        } else {
-               ami_res = "Invalid or unknown command";
-               resultcode = 510;
+               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);
 
                publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
        }
+       ast_module_unref(c->mod);
 
        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;
@@ -3742,6 +4130,8 @@ 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");
@@ -3776,7 +4166,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);
@@ -3854,10 +4244,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;
                                }
@@ -3873,6 +4263,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
                        }
                }
        }
+
        if (agi->speech) {
                ast_speech_destroy(agi->speech);
        }
@@ -4181,23 +4572,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;
 }
 
@@ -4256,17 +4666,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);
@@ -4274,71 +4673,49 @@ 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;
+
+       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);
 
-       message_router = ast_manager_get_message_router();
-       if (!message_router) {
+       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);
+
+       AST_TEST_REGISTER(test_agi_null_docs);
+
+       if (err) {
+               unload_module();
                return AST_MODULE_LOAD_DECLINE;
        }
 
-       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);
+       /* For Optional API. */
+       ast_module_shutdown_ref(AST_MODULE_SELF);
+
+       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,
+       .requires = "res_speech",
+);