mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-03 19:16:46 +00:00
Merging the issue11259 branch.
The purpose of this branch was to take into account "burps" which could cause jitterbuffers to misbehave. One such example is if the L option to Dial() were used to inject audio into a bridged conversation at regular intervals. Since the audio here was not passed through the jitterbuffer, it would cause a gap in the jitterbuffer's timestamps which would cause a frames to be dropped for a brief period. Now ast_generic_bridge will empty and reset the jitterbuffer each time it is called. This causes injected audio to be handled properly. ast_generic_bridge also will empty and reset the jitterbuffer if it receives an AST_CONTROL_SRCUPDATE frame since the change in audio source could negatively affect the jitterbuffer. All of this was made possible by adding a new public API call to the abstract_jb called ast_jb_empty_and_reset. (closes issue #11259) Reported by: plack Tested by: putnopvut git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@135841 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include "asterisk/module.h"
|
#include "asterisk/module.h"
|
||||||
#include "asterisk/lock.h"
|
#include "asterisk/lock.h"
|
||||||
#include "asterisk/app.h"
|
#include "asterisk/app.h"
|
||||||
|
#include "asterisk/utils.h"
|
||||||
|
|
||||||
static char *app = "Skel";
|
static char *app = "Skel";
|
||||||
static char *synopsis =
|
static char *synopsis =
|
||||||
@@ -72,28 +73,26 @@ AST_APP_OPTIONS(app_opts,{
|
|||||||
AST_APP_OPTION_ARG('c', OPTION_C, OPTION_ARG_C),
|
AST_APP_OPTION_ARG('c', OPTION_C, OPTION_ARG_C),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static void *dogballs(void *shit)
|
||||||
|
{
|
||||||
|
ast_log(LOG_NOTICE, "Oh GOD!! I am a thread magician!!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int app_exec(struct ast_channel *chan, void *data)
|
static int app_exec(struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int i;
|
||||||
struct ast_flags flags;
|
|
||||||
struct ast_module_user *u;
|
struct ast_module_user *u;
|
||||||
char *parse, *opts[OPTION_ARG_ARRAY_SIZE];
|
pthread_t thread;
|
||||||
AST_DECLARE_APP_ARGS(args,
|
|
||||||
AST_APP_ARG(dummy);
|
|
||||||
AST_APP_ARG(options);
|
|
||||||
);
|
|
||||||
|
|
||||||
if (ast_strlen_zero(data)) {
|
|
||||||
ast_log(LOG_WARNING, "%s requires an argument (dummy|[options])\n", app);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
u = ast_module_user_add(chan);
|
u = ast_module_user_add(chan);
|
||||||
|
|
||||||
/* Do our thing here */
|
/* Do our thing here */
|
||||||
|
|
||||||
/* We need to make a copy of the input string if we are going to modify it! */
|
for (i = 0; i < 100; ++i) {
|
||||||
|
ast_pthread_create(&thread, NULL, dogballs, NULL);
|
||||||
|
}
|
||||||
|
/*
|
||||||
parse = ast_strdupa(data);
|
parse = ast_strdupa(data);
|
||||||
|
|
||||||
AST_STANDARD_APP_ARGS(args, parse);
|
AST_STANDARD_APP_ARGS(args, parse);
|
||||||
@@ -112,10 +111,10 @@ static int app_exec(struct ast_channel *chan, void *data)
|
|||||||
|
|
||||||
if (ast_test_flag(&flags, OPTION_C))
|
if (ast_test_flag(&flags, OPTION_C))
|
||||||
ast_log(LOG_NOTICE, "Option C is set with : %s\n", opts[OPTION_ARG_C] ? opts[OPTION_ARG_C] : "<unspecified>");
|
ast_log(LOG_NOTICE, "Option C is set with : %s\n", opts[OPTION_ARG_C] ? opts[OPTION_ARG_C] : "<unspecified>");
|
||||||
|
*/
|
||||||
ast_module_user_remove(u);
|
ast_module_user_remove(u);
|
||||||
|
|
||||||
return res;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
|
@@ -212,6 +212,12 @@ void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf);
|
|||||||
*/
|
*/
|
||||||
void ast_jb_get_config(const struct ast_channel *chan, struct ast_jb_conf *conf);
|
void ast_jb_get_config(const struct ast_channel *chan, struct ast_jb_conf *conf);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief drops all frames from a jitterbuffer and resets it
|
||||||
|
* \param c0 one channel of a bridge
|
||||||
|
* \param c1 the other channel of the bridge
|
||||||
|
*/
|
||||||
|
void ast_jb_empty_and_reset(struct ast_channel *c0, struct ast_channel *c1);
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
|
@@ -70,7 +70,8 @@ typedef long (*jb_next_impl)(void *jb);
|
|||||||
typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout);
|
typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout);
|
||||||
/*! \brief Force resynch */
|
/*! \brief Force resynch */
|
||||||
typedef void (*jb_force_resynch_impl)(void *jb);
|
typedef void (*jb_force_resynch_impl)(void *jb);
|
||||||
|
/*! \brief Empty and reset jb */
|
||||||
|
typedef void (*jb_empty_and_reset_impl)(void *jb);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Jitterbuffer implementation private struct.
|
* \brief Jitterbuffer implementation private struct.
|
||||||
@@ -86,6 +87,7 @@ struct ast_jb_impl
|
|||||||
jb_next_impl next;
|
jb_next_impl next;
|
||||||
jb_remove_impl remove;
|
jb_remove_impl remove;
|
||||||
jb_force_resynch_impl force_resync;
|
jb_force_resynch_impl force_resync;
|
||||||
|
jb_empty_and_reset_impl empty_and_reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Implementation functions */
|
/* Implementation functions */
|
||||||
@@ -98,6 +100,7 @@ static int jb_get_fixed(void *jb, struct ast_frame **fout, long now, long interp
|
|||||||
static long jb_next_fixed(void *jb);
|
static long jb_next_fixed(void *jb);
|
||||||
static int jb_remove_fixed(void *jb, struct ast_frame **fout);
|
static int jb_remove_fixed(void *jb, struct ast_frame **fout);
|
||||||
static void jb_force_resynch_fixed(void *jb);
|
static void jb_force_resynch_fixed(void *jb);
|
||||||
|
static void jb_empty_and_reset_fixed(void *jb);
|
||||||
/* adaptive */
|
/* adaptive */
|
||||||
static void * jb_create_adaptive(struct ast_jb_conf *general_config, long resynch_threshold);
|
static void * jb_create_adaptive(struct ast_jb_conf *general_config, long resynch_threshold);
|
||||||
static void jb_destroy_adaptive(void *jb);
|
static void jb_destroy_adaptive(void *jb);
|
||||||
@@ -107,6 +110,7 @@ static int jb_get_adaptive(void *jb, struct ast_frame **fout, long now, long int
|
|||||||
static long jb_next_adaptive(void *jb);
|
static long jb_next_adaptive(void *jb);
|
||||||
static int jb_remove_adaptive(void *jb, struct ast_frame **fout);
|
static int jb_remove_adaptive(void *jb, struct ast_frame **fout);
|
||||||
static void jb_force_resynch_adaptive(void *jb);
|
static void jb_force_resynch_adaptive(void *jb);
|
||||||
|
static void jb_empty_and_reset_adaptive(void *jb);
|
||||||
|
|
||||||
/* Available jb implementations */
|
/* Available jb implementations */
|
||||||
static struct ast_jb_impl avail_impl[] =
|
static struct ast_jb_impl avail_impl[] =
|
||||||
@@ -120,7 +124,8 @@ static struct ast_jb_impl avail_impl[] =
|
|||||||
.get = jb_get_fixed,
|
.get = jb_get_fixed,
|
||||||
.next = jb_next_fixed,
|
.next = jb_next_fixed,
|
||||||
.remove = jb_remove_fixed,
|
.remove = jb_remove_fixed,
|
||||||
.force_resync = jb_force_resynch_fixed
|
.force_resync = jb_force_resynch_fixed,
|
||||||
|
.empty_and_reset = jb_empty_and_reset_fixed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "adaptive",
|
.name = "adaptive",
|
||||||
@@ -131,7 +136,8 @@ static struct ast_jb_impl avail_impl[] =
|
|||||||
.get = jb_get_adaptive,
|
.get = jb_get_adaptive,
|
||||||
.next = jb_next_adaptive,
|
.next = jb_next_adaptive,
|
||||||
.remove = jb_remove_adaptive,
|
.remove = jb_remove_adaptive,
|
||||||
.force_resync = jb_force_resynch_adaptive
|
.force_resync = jb_force_resynch_adaptive,
|
||||||
|
.empty_and_reset = jb_empty_and_reset_adaptive,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -608,11 +614,27 @@ void ast_jb_get_config(const struct ast_channel *chan, struct ast_jb_conf *conf)
|
|||||||
memcpy(conf, &chan->jb.conf, sizeof(*conf));
|
memcpy(conf, &chan->jb.conf, sizeof(*conf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ast_jb_empty_and_reset(struct ast_channel *c0, struct ast_channel *c1)
|
||||||
|
{
|
||||||
|
struct ast_jb *jb0 = &c0->jb;
|
||||||
|
struct ast_jb *jb1 = &c1->jb;
|
||||||
|
int c0_use_jb = ast_test_flag(jb0, JB_USE);
|
||||||
|
int c0_jb_is_created = ast_test_flag(jb0, JB_CREATED);
|
||||||
|
int c1_use_jb = ast_test_flag(jb1, JB_USE);
|
||||||
|
int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED);
|
||||||
|
|
||||||
|
if (c0_use_jb && c0_jb_is_created && jb0->impl->empty_and_reset) {
|
||||||
|
jb0->impl->empty_and_reset(jb0->jbobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c1_use_jb && c1_jb_is_created && jb1->impl->empty_and_reset) {
|
||||||
|
jb1->impl->empty_and_reset(jb1->jbobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Implementation functions */
|
/* Implementation functions */
|
||||||
|
|
||||||
/* fixed */
|
/* fixed */
|
||||||
|
|
||||||
static void * jb_create_fixed(struct ast_jb_conf *general_config, long resynch_threshold)
|
static void * jb_create_fixed(struct ast_jb_conf *general_config, long resynch_threshold)
|
||||||
{
|
{
|
||||||
struct fixed_jb_conf conf;
|
struct fixed_jb_conf conf;
|
||||||
@@ -623,7 +645,6 @@ static void * jb_create_fixed(struct ast_jb_conf *general_config, long resynch_t
|
|||||||
return fixed_jb_new(&conf);
|
return fixed_jb_new(&conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void jb_destroy_fixed(void *jb)
|
static void jb_destroy_fixed(void *jb)
|
||||||
{
|
{
|
||||||
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
|
||||||
@@ -696,6 +717,15 @@ static void jb_force_resynch_fixed(void *jb)
|
|||||||
fixed_jb_set_force_resynch(fixedjb);
|
fixed_jb_set_force_resynch(fixedjb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void jb_empty_and_reset_fixed(void *jb)
|
||||||
|
{
|
||||||
|
struct fixed_jb *fixedjb = jb;
|
||||||
|
struct fixed_jb_frame f;
|
||||||
|
|
||||||
|
while (fixed_jb_remove(fixedjb, &f) == FIXED_JB_OK) {
|
||||||
|
ast_frfree(f.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* adaptive */
|
/* adaptive */
|
||||||
|
|
||||||
@@ -778,3 +808,15 @@ static int jb_remove_adaptive(void *jb, struct ast_frame **fout)
|
|||||||
static void jb_force_resynch_adaptive(void *jb)
|
static void jb_force_resynch_adaptive(void *jb)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void jb_empty_and_reset_adaptive(void *jb)
|
||||||
|
{
|
||||||
|
jitterbuf *adaptivejb = jb;
|
||||||
|
jb_frame f;
|
||||||
|
|
||||||
|
while (jb_getall(adaptivejb, &f) == JB_OK) {
|
||||||
|
ast_frfree(f.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
jb_reset(adaptivejb);
|
||||||
|
}
|
||||||
|
@@ -3779,6 +3779,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
|
|||||||
|
|
||||||
/* Check the need of a jitterbuffer for each channel */
|
/* Check the need of a jitterbuffer for each channel */
|
||||||
jb_in_use = ast_jb_do_usecheck(c0, c1);
|
jb_in_use = ast_jb_do_usecheck(c0, c1);
|
||||||
|
if (jb_in_use)
|
||||||
|
ast_jb_empty_and_reset(c0, c1);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct ast_channel *who, *other;
|
struct ast_channel *who, *other;
|
||||||
@@ -3843,6 +3845,9 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
|
|||||||
case AST_CONTROL_VIDUPDATE:
|
case AST_CONTROL_VIDUPDATE:
|
||||||
case AST_CONTROL_SRCUPDATE:
|
case AST_CONTROL_SRCUPDATE:
|
||||||
ast_indicate_data(other, f->subclass, f->data, f->datalen);
|
ast_indicate_data(other, f->subclass, f->data, f->datalen);
|
||||||
|
if (jb_in_use) {
|
||||||
|
ast_jb_empty_and_reset(c0, c1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*fo = f;
|
*fo = f;
|
||||||
|
@@ -85,7 +85,6 @@ int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout);
|
|||||||
|
|
||||||
void fixed_jb_set_force_resynch(struct fixed_jb *jb);
|
void fixed_jb_set_force_resynch(struct fixed_jb *jb);
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user