All pastes #797982 Raw Edit

Miscellany

public text v1 · immutable
#797982 ·published 2007-11-26 13:52 UTC
rendered paste body
Index: include/asterisk/channel.h
===================================================================
--- include/asterisk/channel.h  (revision 89569)
+++ include/asterisk/channel.h  (working copy)
@@ -573,16 +573,35 @@
 /*! \brief Free a channel datastore structure */
 int ast_channel_datastore_free(struct ast_datastore *datastore);
 
-/*! \brief Add a datastore to a channel */
+/*! 
+ * \brief Add a datastore to a channel 
+ *
+ * \note The channel must be locked before calling this function.
+ */
 int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore);
 
-/*! \brief Remove a datastore from a channel */
+/*! 
+ * \brief Remove a datastore from a channel
+ *
+ * \note The channel must be locked before calling this function.
+ */
 int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore);
 
-/*! \brief Find a datastore on a channel */
+/*! 
+ * \brief Find a datastore on a channel
+ *
+ * \note The channel must be locked before calling this function.
+ */
 struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, char *uid);
 
-/*! \brief Change the state of a channel */
+/*! 
+ * \brief Change the state of a channel 
+ *
+ * \note The channel must be locked before calling this function.
+ *
+ * \todo There are a large number of places throughout the code where this
+ *       function is used without the channel locked.
+ */
 int ast_setstate(struct ast_channel *chan, enum ast_channel_state);
 
 /*! \brief Create a channel structure 
@@ -593,43 +612,61 @@
  */
 struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const int amaflag, const char *name_fmt, ...);
 
-/*! \brief Queue an outgoing frame */
+/*! 
+ * \brief Queue an outgoing frame 
+ *
+ * \note This function will lock the channel as needed.
+ */
 int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f);
 
-/*! \brief Queue a hangup frame */
+/*! 
+ * \brief Queue a hangup frame 
+ * 
+ * \note This function will lock the channel as needed.
+ */
 int ast_queue_hangup(struct ast_channel *chan);
 
 /*!
-  \brief Queue a control frame with payload
-  \param chan channel to queue frame onto
-  \param control type of control frame
-  \return zero on success, non-zero on failure
-*/
+ * \brief Queue a control frame with payload
+ *
+ * \param chan channel to queue frame onto
+ * \param control type of control frame
+ *
+ * \return zero on success, non-zero on failure
+ *
+ * \note This function will lock the channel as needed.
+ */
 int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control);
 
 /*!
-  \brief Queue a control frame with payload
-  \param chan channel to queue frame onto
-  \param control type of control frame
-  \param data pointer to payload data to be included in frame
-  \param datalen number of bytes of payload data
-  \return zero on success, non-zero on failure
-
-  The supplied payload data is copied into the frame, so the caller's copy
-  is not modified nor freed, and the resulting frame will retain a copy of
-  the data even if the caller frees their local copy.
-
-  \note This method should be treated as a 'network transport'; in other
-  words, your frames may be transferred across an IAX2 channel to another
-  system, which may be a different endianness than yours. Because of this,
-  you should ensure that either your frames will never be expected to work
-  across systems, or that you always put your payload data into 'network byte
-  order' before calling this function.
-*/
+ * \brief Queue a control frame with payload
+ * \param chan channel to queue frame onto
+ * \param control type of control frame
+ * \param data pointer to payload data to be included in frame
+ * \param datalen number of bytes of payload data
+ * \return zero on success, non-zero on failure
+ *
+ * The supplied payload data is copied into the frame, so the caller's copy
+ * is not modified nor freed, and the resulting frame will retain a copy of
+ * the data even if the caller frees their local copy.
+ *
+ * \note This method should be treated as a 'network transport'; in other
+ * words, your frames may be transferred across an IAX2 channel to another
+ * system, which may be a different endianness than yours. Because of this,
+ * you should ensure that either your frames will never be expected to work
+ * across systems, or that you always put your payload data into 'network byte
+ * order' before calling this function.
+ *
+ * \note This function will lock the channel as needed.
+ */
 int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control,
                           const void *data, size_t datalen);
 
-/*! \brief Change channel name */
+/*! 
+ * \brief Change channel name 
+ * 
+ * \note The channel must be locked before calling this function.
+ */
 void ast_change_name(struct ast_channel *chan, char *newname);
 
 /*! \brief Free a channel structure */
@@ -682,21 +719,33 @@
  */
 const struct ast_channel_tech *ast_get_channel_tech(const char *name);
 
-/*! \brief Hang up a channel  
+/*! 
+ * \brief Hang up a channel  
+ *
+ * \param chan channel to hang up
+ *
+ * \return Returns 0 on success, -1 on failure.
+ *
  * \note This function performs a hard hangup on a channel.  Unlike the soft-hangup, this function
  * performs all stream stopping, etc, on the channel that needs to end.
  * chan is no longer valid after this call.
- * \param chan channel to hang up
- * \return Returns 0 on success, -1 on failure.
+ *
+ * \note This function will lock the channel as needed.
  */
 int ast_hangup(struct ast_channel *chan);
 
-/*! \brief Softly hangup up a channel 
+/*! 
+ * \brief Softly hangup up a channel 
+ *
  * \param chan channel to be soft-hung-up
+ * \param cause        Ast hangupcause for hangup
+ *
+ * \return Returns 0 regardless
+ *
  * Call the protocol layer, but don't destroy the channel structure (use this if you are trying to
  * safely hangup a channel managed by another thread.
- * \param cause        Ast hangupcause for hangup
- * \return Returns 0 regardless
+ *
+ * \note This function will lock the channel as needed.
  */
 int ast_softhangup(struct ast_channel *chan, int cause);
 
@@ -730,40 +779,63 @@
  */
 void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset);
 
-/*! \brief Answer a ringing call 
+/*! 
+ * \brief Answer a ringing call 
+ *
  * \param chan channel to answer
+ * 
+ * \return Returns 0 on success, -1 on failure
+ *
  * This function answers a channel and handles all necessary call
  * setup functions.
- * \return Returns 0 on success, -1 on failure
+ *
+ * \note This function will lock the channel as needed.
  */
 int ast_answer(struct ast_channel *chan);
 
-/*! \brief Make a call 
+/*! 
+ * \brief Make a call 
+ *
  * \param chan which channel to make the call on
  * \param addr destination of the call
  * \param timeout time to wait on for connect
+ *
+ * \return Returns -1 on failure, 0 on not enough time 
+ *
  * Place a call, take no longer than timeout ms. 
-   \return Returns -1 on failure, 0 on not enough time 
-   (does not automatically stop ringing), and  
-   the number of seconds the connect took otherwise.
-   */
+ * (does not automatically stop ringing), and  
+ * the number of seconds the connect took otherwise.
+ *
+ * \note This function will lock the channel as needed.
+ */
 int ast_call(struct ast_channel *chan, char *addr, int timeout);
 
-/*! \brief Indicates condition of channel 
- * \note Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel
+/*! 
+ * \brief Indicates condition of channel 
+ *
  * \param chan channel to change the indication
  * \param condition which condition to indicate on the channel
  * \return Returns 0 on success, -1 on failure
+ *
+ * Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel
+ * 
+ * \note This function will lock the channel as needed.
  */
 int ast_indicate(struct ast_channel *chan, int condition);
 
-/*! \brief Indicates condition of channel, with payload
- * \note Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel
+/*! 
+ * \brief Indicates condition of channel, with payload
+ * 
  * \param chan channel to change the indication
  * \param condition which condition to indicate on the channel
  * \param data pointer to payload data
  * \param datalen size of payload data
+ *
  * \return Returns 0 on success, -1 on failure
+ *
+ * Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel
+ *
+ * \note This function will lock the channel as needed.
  */
 int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen);
 
@@ -1130,8 +1202,15 @@
  * \retval 0 success
  * \retval -1 failure, or the channel is already being autoserviced
  */
-int ast_autoservice_start(struct ast_channel *chan);
+ #define ast_autoservice_start(c) ast_autoservice_start_full(c, 0)
 
+int ast_autoservice_start_full(struct ast_channel *chan, unsigned int flags);
+
+/* autoservice flags */
+enum {
+       AST_AUTOSERVICE_QUEUE_DTMF = (1 << 0),
+};
+
 /*! 
  * \brief Stop servicing a channel for us...  
  *
Index: main/autoservice.c
===================================================================
--- main/autoservice.c  (revision 89569)
+++ main/autoservice.c  (working copy)
@@ -54,6 +54,8 @@
 
 struct asent {
        struct ast_channel *chan;
+       unsigned int queue_dtmf:1;
+       AST_LIST_HEAD_NOLOCK(, ast_frame) dtmf_frames;
        AST_LIST_ENTRY(asent) list;
 };
 
@@ -85,6 +87,23 @@
                if (chan) {
                        /* Read and ignore anything that occurs */
                        struct ast_frame *f = ast_read(chan);
+
+                       if (f->frametype == AST_FRAME_DTMF_BEGIN || 
+                               f->frametype == AST_FRAME_DTMF_END) {
+                               struct ast_frame *dup_f;
+
+                               /* XXX would be nice to not have to traverse this here, especially
+                                * since we don't know if they actually want the dtmf frames */
+                               AST_LIST_LOCK(&aslist);
+                               AST_LIST_TRAVERSE(&aslist, as, list) {
+                                       if (as->chan != chan)
+                                               continue;
+                                       if (as->queue_dtmf && (dup_f = ast_frdup(f)))
+                                               AST_LIST_INSERT_TAIL(&as->dtmf_frames, dup_f, frame_list);
+                               }
+                               AST_LIST_UNLOCK(&aslist);
+                       }
+
                        if (f)
                                ast_frfree(f);
                }
@@ -93,7 +112,7 @@
        return NULL;
 }
 
-int ast_autoservice_start(struct ast_channel *chan)
+int ast_autoservice_start_full(struct ast_channel *chan, unsigned int flags)
 {
        int res = -1;
        struct asent *as;
@@ -108,6 +127,8 @@
        /* If not, start autoservice on channel */
        if (!as && (as = ast_calloc(1, sizeof(*as)))) {
                as->chan = chan;
+               if (flags & AST_AUTOSERVICE_QUEUE_DTMF)
+                       as->queue_dtmf = 1;
                AST_LIST_INSERT_HEAD(&aslist, as, list);
                res = 0;
                if (asthread == AST_PTHREADT_NULL) { /* need start the thread */
@@ -130,11 +151,16 @@
 {
        int res = -1;
        struct asent *as;
+       AST_LIST_HEAD_NOLOCK(, ast_frame) dtmf_frames;
+       struct ast_frame *f;
 
+       AST_LIST_HEAD_INIT_NOLOCK(&dtmf_frames);
+
        AST_LIST_LOCK(&aslist);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
                if (as->chan == chan) {
                        AST_LIST_REMOVE_CURRENT(&aslist, list);
+                       AST_LIST_APPEND_LIST(&dtmf_frames, &as->dtmf_frames, frame_list);
                        free(as);
                        if (!chan->_softhangup)
                                res = 0;
@@ -148,7 +174,13 @@
        AST_LIST_UNLOCK(&aslist);
 
        /* Wait for it to un-block */
-       while(ast_test_flag(chan, AST_FLAG_BLOCKING))
+       while (ast_test_flag(chan, AST_FLAG_BLOCKING))
                usleep(1000);
+
+       while ((f = AST_LIST_REMOVE_HEAD(&dtmf_frames, frame_list))) {
+               ast_queue_frame(chan, f);
+               ast_frfree(f);
+       }
+
        return res;
 }
Index: main/pbx.c
===================================================================
--- main/pbx.c  (revision 89569)
+++ main/pbx.c  (working copy)
@@ -5608,6 +5608,7 @@
                ms = 10000;
        res = ast_waitfordigit(chan, ms);
        if (!res) {
+               ast_autoservice_start_full(chan, AST_AUTOSERVICE_QUEUE_DTMF);
                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
                        if (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
@@ -5619,6 +5620,7 @@
                        ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
                        res = -1;
                }
+               ast_autoservice_stop(chan);
        }
 
        if (ast_test_flag(&flags, WAITEXTEN_MOH))