Merge "translate: Show sample rate for silk, speex, and slin in translation table."
authorJoshua Colp <jcolp@digium.com>
Tue, 28 Nov 2017 18:37:51 +0000 (12:37 -0600)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Tue, 28 Nov 2017 18:37:51 +0000 (12:37 -0600)
.gitreview
addons/ooh323c/src/ooCalls.c
configs/samples/features.conf.sample
include/asterisk/cli.h
main/asterisk.c
main/cli.c
res/ari/resource_bridges.c
res/res_rtp_asterisk.c
tests/test_substitution.c
third-party/pjproject/patches/0040-183_without_to_tag.patch [new file with mode: 0644]

index f9ef050..d38061d 100644 (file)
@@ -2,3 +2,4 @@
 host=gerrit.asterisk.org
 port=29418
 project=asterisk.git
+defaultbranch=master
index 26dc63e..c920e6a 100644 (file)
@@ -29,6 +29,7 @@
 #include "ooGkClient.h"
 #include "ooh323ep.h"
 #include "ooCalls.h"
+#include "ooCmdChannel.h"
 
 /** Global endpoint structure */
 extern OOH323EndPoint gH323ep;
@@ -173,6 +174,7 @@ OOH323CallData* ooCreateCall(char* type, char*callToken)
    call->msdRetries = 0;
    call->pFastStartRes = NULL;
    call->usrData = NULL;
+   ooCreateCallCmdConnection(call);
    OOTRACEINFO3("Created a new call (%s, %s)\n", call->callType, 
                  call->callToken);
    /* Add new call to calllist */
index 223d693..5806e4c 100644 (file)
@@ -72,8 +72,8 @@
 ;                   means run the application on the opposite channel from the one that
 ;                   has activated the feature.
 ;  ActivatedBy   -> ActivatedBy is no longer honored.  The feature is activated by which
-;                   channel DYNAMIC_FEATURES includes the feature is on.  Use predial
-;                   to set different values of DYNAMIC_FEATURES on the channels.
+;                   channel DYNAMIC_FEATURES includes the feature is on.  Use a pre-dial
+;                   handler to set different values for DYNAMIC_FEATURES on the channels.
 ;                   Historic values are: "caller", "callee", and "both".
 ;  Application   -> This is the application to execute.
 ;  AppArguments  -> These are the arguments to be passed into the application.  If you need
index 3ed88eb..c75fc29 100644 (file)
@@ -287,6 +287,9 @@ int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len);
  * Useful for readline, that's about it
  * \retval 0 on success
  * \retval -1 on failure
+ *
+ * Only call this function to proxy the CLI generator to
+ * another.
  */
 char *ast_cli_generator(const char *, const char *, int);
 
@@ -302,6 +305,9 @@ int ast_cli_generatornummatches(const char *, const char *);
  * Subsequent entries are all possible values, followed by a NULL.
  * All strings and the array itself are malloc'ed and must be freed
  * by the caller.
+ *
+ * \warning This function cannot be called recursively so it will always
+ *          fail if called from a CLI_GENERATE callback.
  */
 char **ast_cli_completion_matches(const char *, const char *);
 
@@ -323,10 +329,30 @@ char **ast_cli_completion_matches(const char *, const char *);
  *       by the caller.
  *
  * \note The vector is sorted and does not contain any duplicates.
+ *
+ * \warning This function cannot be called recursively so it will always
+ *          fail if called from a CLI_GENERATE callback.
  */
 struct ast_vector_string *ast_cli_completion_vector(const char *text, const char *word);
 
 /*!
+ * \brief Add a result to a request for completion options.
+ *
+ * \param value A completion option text.
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ *
+ * This is an alternative to returning individual values from CLI_GENERATE.  Instead
+ * of repeatedly being asked for the next match and having to start over, you can
+ * call this function repeatedly from your own stateful loop.  When all matches have
+ * been added you can return NULL from the CLI_GENERATE function.
+ *
+ * \note This function always eventually results in calling ast_free on \a value.
+ */
+int ast_cli_completion_add(char *value);
+
+/*!
  * \brief Command completion for the list of active channels.
  *
  * This can be called from a CLI command completion function that wants to
index 77046f2..db80670 100644 (file)
@@ -3001,121 +3001,70 @@ static char *cli_prompt(EditLine *editline)
        return ast_str_buffer(prompt);
 }
 
-static void destroy_match_list(char **match_list, int matches)
+static struct ast_vector_string *ast_el_strtoarr(char *buf)
 {
-       if (match_list) {
-               int idx;
+       char *retstr;
+       struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec));
 
-               for (idx = 0; idx < matches; ++idx) {
-                       ast_free(match_list[idx]);
-               }
-               ast_free(match_list);
+       if (!vec) {
+               return NULL;
        }
-}
-
-static char **ast_el_strtoarr(char *buf)
-{
-       char *retstr;
-       char **match_list = NULL;
-       char **new_list;
-       size_t match_list_len = 1;
-       int matches = 0;
 
        while ((retstr = strsep(&buf, " "))) {
                if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) {
                        break;
                }
-               if (matches + 1 >= match_list_len) {
-                       match_list_len <<= 1;
-                       new_list = ast_realloc(match_list, match_list_len * sizeof(char *));
-                       if (!new_list) {
-                               destroy_match_list(match_list, matches);
-                               return NULL;
-                       }
-                       match_list = new_list;
+
+               /* Older daemons sent duplicates. */
+               if (AST_VECTOR_GET_CMP(vec, retstr, strcasecmp)) {
+                       continue;
                }
 
                retstr = ast_strdup(retstr);
-               if (!retstr) {
-                       destroy_match_list(match_list, matches);
-                       return NULL;
+               /* Older daemons sent unsorted. */
+               if (!retstr || AST_VECTOR_ADD_SORTED(vec, retstr, strcasecmp)) {
+                       ast_free(retstr);
+                       goto vector_cleanup;
                }
-               match_list[matches++] = retstr;
        }
 
-       if (!match_list) {
-               return NULL;
+       if (!AST_VECTOR_SIZE(vec)) {
+               goto vector_cleanup;
        }
 
-       if (matches >= match_list_len) {
-               new_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *));
-               if (!new_list) {
-                       destroy_match_list(match_list, matches);
-                       return NULL;
-               }
-               match_list = new_list;
-       }
+       return vec;
 
-       match_list[matches] = NULL;
+vector_cleanup:
+       AST_VECTOR_CALLBACK_VOID(vec, ast_free);
+       AST_VECTOR_PTR_FREE(vec);
 
-       return match_list;
-}
-
-static int ast_el_sort_compare(const void *i1, const void *i2)
-{
-       char *s1, *s2;
-
-       s1 = ((char **)i1)[0];
-       s2 = ((char **)i2)[0];
-
-       return strcasecmp(s1, s2);
+       return NULL;
 }
 
-static int ast_cli_display_match_list(char **matches, int len, int max)
+static void ast_cli_display_match_list(struct ast_vector_string *matches, int max)
 {
-       int i, idx, limit, count;
-       int screenwidth = 0;
-       int numoutput = 0, numoutputline = 0;
-
-       screenwidth = ast_get_termcols(STDOUT_FILENO);
-
+       int idx = 1;
        /* find out how many entries can be put on one line, with two spaces between strings */
-       limit = screenwidth / (max + 2);
-       if (limit == 0)
-               limit = 1;
-
-       /* how many lines of output */
-       count = len / limit;
-       if (count * limit < len)
-               count++;
+       int limit = ast_get_termcols(STDOUT_FILENO) / (max + 2);
 
-       idx = 1;
-
-       qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
-
-       for (; count > 0; count--) {
-               numoutputline = 0;
-               for (i = 0; i < limit && matches[idx]; i++, idx++) {
+       if (limit == 0) {
+               limit = 1;
+       }
 
-                       /* Don't print dupes */
-                       if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
-                               i--;
-                               ast_free(matches[idx]);
-                               matches[idx] = NULL;
-                               continue;
-                       }
+       for (;;) {
+               int numoutputline;
 
-                       numoutput++;
+               for (numoutputline = 0; numoutputline < limit && idx < AST_VECTOR_SIZE(matches); idx++) {
                        numoutputline++;
-                       fprintf(stdout, "%-*s  ", max, matches[idx]);
-                       ast_free(matches[idx]);
-                       matches[idx] = NULL;
+                       fprintf(stdout, "%-*s  ", max, AST_VECTOR_GET(matches, idx));
+               }
+
+               if (!numoutputline) {
+                       break;
                }
-               if (numoutputline > 0)
-                       fprintf(stdout, "\n");
-       }
 
-       return numoutput;
+               fprintf(stdout, "\n");
+       }
 }
 
 
@@ -3123,10 +3072,9 @@ static char *cli_complete(EditLine *editline, int ch)
 {
        int len = 0;
        char *ptr;
-       int nummatches = 0;
-       char **matches;
+       struct ast_vector_string *matches;
        int retval = CC_ERROR;
-       char buf[2048], savechr;
+       char savechr;
        int res;
 
        LineInfo *lf = (LineInfo *)el_line(editline);
@@ -3147,96 +3095,90 @@ static char *cli_complete(EditLine *editline, int ch)
        len = lf->cursor - ptr;
 
        if (ast_opt_remote) {
-               snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
-               fdsend(ast_consock, buf);
-               if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
-                       return (char*)(CC_ERROR);
+#define CMD_MATCHESARRAY "_COMMAND MATCHESARRAY \"%s\" \"%s\""
+               char *mbuf;
+               char *new_mbuf;
+               int mlen = 0, maxmbuf = 2048;
+
+               /* Start with a 2048 byte buffer */
+               mbuf = ast_malloc(maxmbuf);
+
+               /* This will run snprintf twice at most. */
+               while (mbuf && (mlen = snprintf(mbuf, maxmbuf, CMD_MATCHESARRAY, lf->buffer, ptr)) > maxmbuf) {
+                       /* Return value does not include space for NULL terminator. */
+                       maxmbuf = mlen + 1;
+                       ast_free(mbuf);
+                       mbuf = ast_malloc(maxmbuf);
                }
-               buf[res] = '\0';
-               nummatches = atoi(buf);
-
-               if (nummatches > 0) {
-                       char *mbuf;
-                       char *new_mbuf;
-                       int mlen = 0, maxmbuf = 2048;
-
-                       /* Start with a 2048 byte buffer */
-                       if (!(mbuf = ast_malloc(maxmbuf))) {
-                               *((char *) lf->cursor) = savechr;
-                               return (char *)(CC_ERROR);
-                       }
-                       snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
-                       fdsend(ast_consock, buf);
-                       res = 0;
-                       mbuf[0] = '\0';
-                       while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
-                               if (mlen + 1024 > maxmbuf) {
-                                       /* Every step increment buffer 1024 bytes */
-                                       maxmbuf += 1024;
-                                       new_mbuf = ast_realloc(mbuf, maxmbuf);
-                                       if (!new_mbuf) {
-                                               ast_free(mbuf);
-                                               *((char *) lf->cursor) = savechr;
-                                               return (char *)(CC_ERROR);
-                                       }
-                                       mbuf = new_mbuf;
+
+               if (!mbuf) {
+                       *((char *) lf->cursor) = savechr;
+
+                       return (char *)(CC_ERROR);
+               }
+
+               fdsend(ast_consock, mbuf);
+               res = 0;
+               mlen = 0;
+               mbuf[0] = '\0';
+
+               while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
+                       if (mlen + 1024 > maxmbuf) {
+                               /* Expand buffer to the next 1024 byte increment. */
+                               maxmbuf = mlen + 1024;
+                               new_mbuf = ast_realloc(mbuf, maxmbuf);
+                               if (!new_mbuf) {
+                                       ast_free(mbuf);
+                                       *((char *) lf->cursor) = savechr;
+
+                                       return (char *)(CC_ERROR);
                                }
-                               /* Only read 1024 bytes at a time */
-                               res = read(ast_consock, mbuf + mlen, 1024);
-                               if (res > 0)
-                                       mlen += res;
+                               mbuf = new_mbuf;
                        }
-                       mbuf[mlen] = '\0';
+                       /* Only read 1024 bytes at a time */
+                       res = read(ast_consock, mbuf + mlen, 1024);
+                       if (res > 0) {
+                               mlen += res;
+                       }
+               }
+               mbuf[mlen] = '\0';
 
-                       matches = ast_el_strtoarr(mbuf);
-                       ast_free(mbuf);
-               } else
-                       matches = (char **) NULL;
+               matches = ast_el_strtoarr(mbuf);
+               ast_free(mbuf);
        } else {
-               char **p, *oldbuf=NULL;
-               nummatches = 0;
-               matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
-               for (p = matches; p && *p; p++) {
-                       if (!oldbuf || strcmp(*p,oldbuf))
-                               nummatches++;
-                       oldbuf = *p;
-               }
+               matches = ast_cli_completion_vector((char *)lf->buffer, ptr);
        }
 
        if (matches) {
                int i;
-               int matches_num, maxlen, match_len;
+               int maxlen, match_len;
+               const char *best_match = AST_VECTOR_GET(matches, 0);
 
-               if (matches[0][0] != '\0') {
+               if (!ast_strlen_zero(best_match)) {
                        el_deletestr(editline, (int) len);
-                       el_insertstr(editline, matches[0]);
+                       el_insertstr(editline, best_match);
                        retval = CC_REFRESH;
                }
 
-               if (nummatches == 1) {
+               if (AST_VECTOR_SIZE(matches) == 2) {
                        /* Found an exact match */
                        el_insertstr(editline, " ");
                        retval = CC_REFRESH;
                } else {
                        /* Must be more than one match */
-                       for (i = 1, maxlen = 0; matches[i]; i++) {
-                               match_len = strlen(matches[i]);
-                               if (match_len > maxlen)
+                       for (i = 1, maxlen = 0; i < AST_VECTOR_SIZE(matches); i++) {
+                               match_len = strlen(AST_VECTOR_GET(matches, i));
+                               if (match_len > maxlen) {
                                        maxlen = match_len;
+                               }
                        }
-                       matches_num = i - 1;
-                       if (matches_num >1) {
-                               fprintf(stdout, "\n");
-                               ast_cli_display_match_list(matches, nummatches, maxlen);
-                               retval = CC_REDISPLAY;
-                       } else {
-                               el_insertstr(editline," ");
-                               retval = CC_REFRESH;
-                       }
+
+                       fprintf(stdout, "\n");
+                       ast_cli_display_match_list(matches, maxlen);
+                       retval = CC_REDISPLAY;
                }
-               for (i = 0; matches[i]; i++)
-                       ast_free(matches[i]);
-               ast_free(matches);
+               AST_VECTOR_CALLBACK_VOID(matches, ast_free);
+               AST_VECTOR_PTR_FREE(matches);
        }
 
        *((char *) lf->cursor) = savechr;
index eae14ad..0f023b2 100644 (file)
@@ -2475,18 +2475,17 @@ static char *parse_args(const char *s, int *argc, const char *argv[], int max, i
 /*! \brief Return the number of unique matches for the generator */
 int ast_cli_generatornummatches(const char *text, const char *word)
 {
-       int matches = 0, i = 0;
-       char *buf = NULL, *oldbuf = NULL;
-
-       while ((buf = ast_cli_generator(text, word, i++))) {
-               if (!oldbuf || strcmp(buf,oldbuf))
-                       matches++;
-               if (oldbuf)
-                       ast_free(oldbuf);
-               oldbuf = buf;
-       }
-       if (oldbuf)
-               ast_free(oldbuf);
+       int matches;
+       struct ast_vector_string *vec = ast_cli_completion_vector(text, word);
+
+       if (!vec) {
+               return 0;
+       }
+
+       matches = AST_VECTOR_SIZE(vec) - 1;
+       AST_VECTOR_CALLBACK_VOID(vec, ast_free);
+       AST_VECTOR_PTR_FREE(vec);
+
        return matches;
 }
 
@@ -2513,6 +2512,44 @@ char **ast_cli_completion_matches(const char *text, const char *word)
        return match_list;
 }
 
+AST_THREADSTORAGE_RAW(completion_storage);
+
+/*!
+ * \internal
+ * \brief Add a value to the vector.
+ *
+ * \param vec Vector to add \a value to. Must be from threadstorage.
+ * \param value The value to add.
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+static int cli_completion_vector_add(struct ast_vector_string *vec, char *value)
+{
+       if (!value) {
+               return 0;
+       }
+
+       if (!vec || AST_VECTOR_ADD_SORTED(vec, value, strcasecmp)) {
+               if (vec) {
+                       ast_threadstorage_set_ptr(&completion_storage, NULL);
+
+                       AST_VECTOR_CALLBACK_VOID(vec, ast_free);
+                       AST_VECTOR_FREE(vec);
+               }
+               ast_free(value);
+
+               return -1;
+       }
+
+       return 0;
+}
+
+int ast_cli_completion_add(char *value)
+{
+       return cli_completion_vector_add(ast_threadstorage_get_ptr(&completion_storage), value);
+}
+
 struct ast_vector_string *ast_cli_completion_vector(const char *text, const char *word)
 {
        char *retstr, *prevstr;
@@ -2520,13 +2557,23 @@ struct ast_vector_string *ast_cli_completion_vector(const char *text, const char
        size_t which = 0;
        struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec));
 
+       /* Recursion into this function is a coding error. */
+       ast_assert(!ast_threadstorage_get_ptr(&completion_storage));
+
        if (!vec) {
                return NULL;
        }
 
+       if (ast_threadstorage_set_ptr(&completion_storage, vec)) {
+               ast_log(LOG_ERROR, "Failed to initialize threadstorage for completion.\n");
+               ast_free(vec);
+
+               return NULL;
+       }
+
        while ((retstr = ast_cli_generator(text, word, which)) != NULL) {
-               if (AST_VECTOR_ADD_SORTED(vec, retstr, strcasecmp)) {
-                       ast_free(retstr);
+               if (cli_completion_vector_add(vec, retstr)) {
+                       ast_threadstorage_set_ptr(&completion_storage, NULL);
 
                        goto vector_cleanup;
                }
@@ -2534,6 +2581,8 @@ struct ast_vector_string *ast_cli_completion_vector(const char *text, const char
                ++which;
        }
 
+       ast_threadstorage_set_ptr(&completion_storage, NULL);
+
        if (!AST_VECTOR_SIZE(vec)) {
                AST_VECTOR_PTR_FREE(vec);
 
@@ -2572,6 +2621,7 @@ struct ast_vector_string *ast_cli_completion_vector(const char *text, const char
        retstr = ast_strndup(AST_VECTOR_GET(vec, 0), max_equal);
        if (!retstr || AST_VECTOR_INSERT_AT(vec, 0, retstr)) {
                ast_free(retstr);
+
                goto vector_cleanup;
        }
 
index cd289aa..a320c29 100644 (file)
@@ -968,13 +968,12 @@ void ast_ari_bridges_create_with_id(struct ast_variable *headers,
 
        if (bridge) {
                /* update */
-               if (!ast_strlen_zero(args->name)) {
-                       if (!strcmp(args->name, bridge->name)) {
-                               ast_ari_response_error(
-                                       response, 500, "Internal Error",
-                                       "Changing bridge name is not implemented");
-                               return;
-                       }
+               if (!ast_strlen_zero(args->name)
+                       && strcmp(args->name, bridge->name)) {
+                       ast_ari_response_error(
+                               response, 500, "Internal Error",
+                               "Changing bridge name is not implemented");
+                       return;
                }
                if (!ast_strlen_zero(args->type)) {
                        ast_ari_response_error(
index 839753e..2730611 100644 (file)
 #define ZFONE_PROFILE_ID 0x505a
 
 #define DEFAULT_LEARNING_MIN_SEQUENTIAL 4
+/*!
+ * \brief Calculate the min learning duration in ms.
+ *
+ * \details
+ * The min supported packet size represents 10 ms and we need to account
+ * for some jitter and fast clocks while learning.  Some messed up devices
+ * have very bad jitter for a small packet sample size.  Jitter can also
+ * be introduced by the network itself.
+ *
+ * So we'll allow packets to come in every 9ms on average for fast clocking
+ * with the last one coming in 5ms early for jitter.
+ */
+#define CALC_LEARNING_MIN_DURATION(count) (((count) - 1) * 9 - 5)
+#define DEFAULT_LEARNING_MIN_DURATION CALC_LEARNING_MIN_DURATION(DEFAULT_LEARNING_MIN_SEQUENTIAL)
 
 #define SRTP_MASTER_KEY_LEN 16
 #define SRTP_MASTER_SALT_LEN 14
@@ -151,6 +165,7 @@ static int nochecksums;
 #endif
 static int strictrtp = DEFAULT_STRICT_RTP; /*!< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */
 static int learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; /*!< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */
+static int learning_min_duration = DEFAULT_LEARNING_MIN_DURATION; /*!< Lowest acceptable timeout between the first and the last sequential RTP frame. */
 #ifdef HAVE_PJPROJECT
 static int icesupport = DEFAULT_ICESUPPORT;
 static struct sockaddr_in stunaddr;
@@ -231,7 +246,7 @@ static AST_RWLIST_HEAD_STATIC(host_candidates, ast_ice_host_candidate);
 struct rtp_learning_info {
        struct ast_sockaddr proposed_address;   /*!< Proposed remote address for strict RTP */
        struct timeval start;   /*!< The time learning mode was started */
-       struct timeval received; /*!< The time of the last received packet */
+       struct timeval received; /*!< The time of the first received packet */
        int max_seq;    /*!< The highest sequence number received */
        int packets;    /*!< The number of remaining packets before the source is accepted */
 };
@@ -3065,25 +3080,28 @@ static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq)
  */
 static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq)
 {
-       /*
-        * During the learning mode the minimum amount of media we'll accept is
-        * 10ms so give a reasonable 5ms buffer just in case we get it sporadically.
-        */
-       if (!ast_tvzero(info->received) && ast_tvdiff_ms(ast_tvnow(), info->received) < 5) {
-               /*
-                * Reject a flood of packets as acceptable for learning.
-                * Reset the needed packets.
-                */
-               info->packets = learning_min_sequential - 1;
-       } else if (seq == (uint16_t) (info->max_seq + 1)) {
+       if (seq == (uint16_t) (info->max_seq + 1)) {
                /* packet is in sequence */
                info->packets--;
        } else {
                /* Sequence discontinuity; reset */
                info->packets = learning_min_sequential - 1;
+               info->received = ast_tvnow();
+       }
+
+       /*
+        * Protect against packet floods by checking that we
+        * received the packet sequence in at least the minimum
+        * allowed time.
+        */
+       if (ast_tvzero(info->received)) {
+               info->received = ast_tvnow();
+       } else if (!info->packets && (ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration )) {
+               /* Packet flood; reset */
+               info->packets = learning_min_sequential - 1;
+               info->received = ast_tvnow();
        }
        info->max_seq = seq;
-       info->received = ast_tvnow();
 
        return info->packets;
 }
@@ -7153,6 +7171,7 @@ static int rtp_reload(int reload)
        dtmftimeout = DEFAULT_DTMF_TIMEOUT;
        strictrtp = DEFAULT_STRICT_RTP;
        learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL;
+       learning_min_duration = DEFAULT_LEARNING_MIN_DURATION;
 
        /** This resource is not "reloaded" so much as unloaded and loaded again.
         * In the case of the TURN related variables, the memory referenced by a
@@ -7217,10 +7236,12 @@ static int rtp_reload(int reload)
                strictrtp = ast_true(s);
        }
        if ((s = ast_variable_retrieve(cfg, "general", "probation"))) {
-               if ((sscanf(s, "%d", &learning_min_sequential) <= 0) || learning_min_sequential <= 0) {
+               if ((sscanf(s, "%d", &learning_min_sequential) != 1) || learning_min_sequential <= 1) {
                        ast_log(LOG_WARNING, "Value for 'probation' could not be read, using default of '%d' instead\n",
                                DEFAULT_LEARNING_MIN_SEQUENTIAL);
+                       learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL;
                }
+               learning_min_duration = CALC_LEARNING_MIN_DURATION(learning_min_sequential);
        }
 #ifdef HAVE_PJPROJECT
        if ((s = ast_variable_retrieve(cfg, "general", "icesupport"))) {
index 3a1dc1f..8b9a164 100644 (file)
@@ -43,6 +43,7 @@
 #include "asterisk/stringfields.h"
 #include "asterisk/threadstorage.h"
 #include "asterisk/test.h"
+#include "asterisk/vector.h"
 
 static enum ast_test_result_state test_chan_integer(struct ast_test *test,
                struct ast_channel *c, int *ifield, const char *expression)
@@ -225,6 +226,7 @@ AST_TEST_DEFINE(test_substitution)
        struct ast_channel *c;
        int i;
        enum ast_test_result_state res = AST_TEST_PASS;
+       struct ast_vector_string *funcs;
 
        switch (cmd) {
        case TEST_INIT:
@@ -302,11 +304,12 @@ AST_TEST_DEFINE(test_substitution)
 #undef TEST
 
        /* For testing dialplan functions */
-       for (i = 0; ; i++) {
-               char *cmd = ast_cli_generator("core show function", "", i);
-               if (cmd == NULL) {
-                       break;
-               }
+       funcs = ast_cli_completion_vector("core show function", "");
+
+       /* Skip "best match" element 0 */
+       for (i = 1; funcs && i < AST_VECTOR_SIZE(funcs); i++) {
+               char *cmd = AST_VECTOR_GET(funcs, i);
+
                if (strcmp(cmd, "CHANNEL") && strcmp(cmd, "CALLERID") && strncmp(cmd, "CURL", 4) &&
                                strncmp(cmd, "AES", 3) && strncmp(cmd, "BASE64", 6) &&
                                strcmp(cmd, "CDR") && strcmp(cmd, "ENV") && strcmp(cmd, "GLOBAL") &&
@@ -321,10 +324,14 @@ AST_TEST_DEFINE(test_substitution)
                                }
                        }
                }
-               ast_free(cmd);
        }
 
+       if (funcs) {
+               AST_VECTOR_CALLBACK_VOID(funcs, ast_free);
+               AST_VECTOR_PTR_FREE(funcs);
+       }
        ast_hangup(c);
+
        return res;
 }
 
diff --git a/third-party/pjproject/patches/0040-183_without_to_tag.patch b/third-party/pjproject/patches/0040-183_without_to_tag.patch
new file mode 100644 (file)
index 0000000..e8692fe
--- /dev/null
@@ -0,0 +1,17 @@
+diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
+index c9686a0..fc52a63 100644
+--- a/pjsip/src/pjsip-ua/sip_inv.c
++++ b/pjsip/src/pjsip-ua/sip_inv.c
+@@ -4156,9 +4156,10 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
+                   status = pjsip_inv_send_msg(inv, cancel);
+           }
+-          if (dlg->remote.info->tag.slen) {
++          if (tsx->status_code != 100) {
+-              inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
++              if (dlg->remote.info->tag.slen)
++                  inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
+               inv_check_sdp_in_incoming_msg(inv, tsx, 
+                                             e->body.tsx_state.src.rdata);