Sat Apr 26 2014 22:01:43

Asterisk developer's documentation


abstract_jb.h File Reference

Common implementation-independent jitterbuffer stuff. More...

#include <sys/time.h>
#include "asterisk/format.h"
Include dependency graph for abstract_jb.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_jb
 General jitterbuffer state. More...
struct  ast_jb_conf
 General jitterbuffer configuration. More...
struct  ast_jb_impl
 Jitterbuffer implementation struct. More...

Defines

#define AST_JB_CONF_ENABLE   "enable"
#define AST_JB_CONF_FORCE   "force"
#define AST_JB_CONF_IMPL   "impl"
#define AST_JB_CONF_LOG   "log"
#define AST_JB_CONF_MAX_SIZE   "maxsize"
#define AST_JB_CONF_PREFIX   "jb"
#define AST_JB_CONF_RESYNCH_THRESHOLD   "resyncthreshold"
#define AST_JB_CONF_TARGET_EXTRA   "targetextra"
#define AST_JB_IMPL_NAME_SIZE   12

Typedefs

typedef void *(* jb_create_impl )(struct ast_jb_conf *general_config)
 Create.
typedef void(* jb_destroy_impl )(void *jb)
 Destroy.
typedef void(* jb_empty_and_reset_impl )(void *jb)
 Empty and reset jb.
typedef void(* jb_force_resynch_impl )(void *jb)
 Force resynch.
typedef int(* jb_get_impl )(void *jb, struct ast_frame **fout, long now, long interpl)
 Get frame for now.
typedef long(* jb_next_impl )(void *jb)
 Get next.
typedef int(* jb_put_first_impl )(void *jb, struct ast_frame *fin, long now)
 Put first frame.
typedef int(* jb_put_impl )(void *jb, struct ast_frame *fin, long now)
 Put frame.
typedef int(* jb_remove_impl )(void *jb, struct ast_frame **fout)
 Remove first frame.

Enumerations

enum  { AST_JB_ENABLED = (1 << 0), AST_JB_FORCED = (1 << 1), AST_JB_LOG = (1 << 2) }
enum  { AST_JB_IMPL_OK, AST_JB_IMPL_DROP, AST_JB_IMPL_INTERP, AST_JB_IMPL_NOFRAME }
enum  ast_jb_type { AST_JB_FIXED, AST_JB_ADAPTIVE }

Functions

void ast_jb_configure (struct ast_channel *chan, const struct ast_jb_conf *conf)
 Configures a jitterbuffer on a channel.
void ast_jb_destroy (struct ast_channel *chan)
 Destroys jitterbuffer on a channel.
int ast_jb_do_usecheck (struct ast_channel *c0, struct ast_channel *c1)
 Checks the need of a jb use in a generic bridge.
void ast_jb_empty_and_reset (struct ast_channel *c0, struct ast_channel *c1)
 drops all frames from a jitterbuffer and resets it
void ast_jb_get_and_deliver (struct ast_channel *c0, struct ast_channel *c1)
 Deliver the queued frames that should be delivered now for both channels.
void ast_jb_get_config (const struct ast_channel *chan, struct ast_jb_conf *conf)
 Copies a channel's jitterbuffer configuration.
struct ast_jb_implast_jb_get_impl (enum ast_jb_type type)
int ast_jb_get_when_to_wakeup (struct ast_channel *c0, struct ast_channel *c1, int time_left)
 Calculates the time, left to the closest delivery moment in a bridge.
int ast_jb_put (struct ast_channel *chan, struct ast_frame *f)
 Puts a frame into a channel jitterbuffer.
int ast_jb_read_conf (struct ast_jb_conf *conf, const char *varname, const char *value)
 Sets jitterbuffer configuration property.

Detailed Description

Common implementation-independent jitterbuffer stuff.

Author:
Slav Klenov <slav@securax.org>

Definition in file abstract_jb.h.


Define Documentation

#define AST_JB_CONF_ENABLE   "enable"

Definition at line 85 of file abstract_jb.h.

Referenced by ast_jb_read_conf().

#define AST_JB_CONF_FORCE   "force"

Definition at line 86 of file abstract_jb.h.

Referenced by ast_jb_read_conf().

#define AST_JB_CONF_IMPL   "impl"

Definition at line 90 of file abstract_jb.h.

Referenced by ast_jb_read_conf().

#define AST_JB_CONF_LOG   "log"

Definition at line 91 of file abstract_jb.h.

Referenced by ast_jb_read_conf().

#define AST_JB_CONF_MAX_SIZE   "maxsize"

Definition at line 87 of file abstract_jb.h.

Referenced by ast_jb_read_conf().

#define AST_JB_CONF_PREFIX   "jb"

Definition at line 84 of file abstract_jb.h.

Referenced by ast_jb_read_conf().

#define AST_JB_CONF_RESYNCH_THRESHOLD   "resyncthreshold"

Definition at line 88 of file abstract_jb.h.

Referenced by ast_jb_read_conf().

#define AST_JB_CONF_TARGET_EXTRA   "targetextra"

Definition at line 89 of file abstract_jb.h.

Referenced by ast_jb_read_conf().

#define AST_JB_IMPL_NAME_SIZE   12

Definition at line 63 of file abstract_jb.h.

Referenced by create_jb().


Typedef Documentation

typedef void*(* jb_create_impl)(struct ast_jb_conf *general_config)

Create.

Definition at line 95 of file abstract_jb.h.

typedef void(* jb_destroy_impl)(void *jb)

Destroy.

Definition at line 97 of file abstract_jb.h.

typedef void(* jb_empty_and_reset_impl)(void *jb)

Empty and reset jb.

Definition at line 111 of file abstract_jb.h.

typedef void(* jb_force_resynch_impl)(void *jb)

Force resynch.

Definition at line 109 of file abstract_jb.h.

typedef int(* jb_get_impl)(void *jb, struct ast_frame **fout, long now, long interpl)

Get frame for now.

Definition at line 103 of file abstract_jb.h.

typedef long(* jb_next_impl)(void *jb)

Get next.

Definition at line 105 of file abstract_jb.h.

typedef int(* jb_put_first_impl)(void *jb, struct ast_frame *fin, long now)

Put first frame.

Definition at line 99 of file abstract_jb.h.

typedef int(* jb_put_impl)(void *jb, struct ast_frame *fin, long now)

Put frame.

Definition at line 101 of file abstract_jb.h.

typedef int(* jb_remove_impl)(void *jb, struct ast_frame **fout)

Remove first frame.

Definition at line 107 of file abstract_jb.h.


Enumeration Type Documentation

anonymous enum
Enumerator:
AST_JB_ENABLED 
AST_JB_FORCED 
AST_JB_LOG 

Definition at line 44 of file abstract_jb.h.

     {
   AST_JB_ENABLED = (1 << 0),
   AST_JB_FORCED =  (1 << 1),
   AST_JB_LOG =     (1 << 2)
};
anonymous enum

Abstract return codes

Enumerator:
AST_JB_IMPL_OK 
AST_JB_IMPL_DROP 
AST_JB_IMPL_INTERP 
AST_JB_IMPL_NOFRAME 

Definition at line 56 of file abstract_jb.h.

Enumerator:
AST_JB_FIXED 
AST_JB_ADAPTIVE 

Definition at line 50 of file abstract_jb.h.


Function Documentation

void ast_jb_configure ( struct ast_channel chan,
const struct ast_jb_conf conf 
)

Configures a jitterbuffer on a channel.

Parameters:
chanchannel to configure.
confconfiguration to apply.

Called from a channel driver when a channel is created and its jitterbuffer needs to be configured.

Definition at line 571 of file abstract_jb.c.

References ast_channel_jb().

Referenced by __oh323_rtp_create(), __oh323_update_info(), alsa_new(), console_new(), dahdi_new(), gtalk_new(), jingle_new(), local_new(), mgcp_new(), misdn_new(), oss_new(), sip_new(), skinny_new(), and unistim_new().

{
   memcpy(&ast_channel_jb(chan)->conf, conf, sizeof(*conf));
}
void ast_jb_destroy ( struct ast_channel chan)

Destroys jitterbuffer on a channel.

Parameters:
chanchannel.

Called from ast_channel_free() when a channel is destroyed.

Definition at line 491 of file abstract_jb.c.

References ast_channel_jb(), ast_channel_name(), ast_clear_flag, ast_frfree, AST_JB_IMPL_OK, ast_test_flag, ast_verb, ast_jb_impl::destroy, f, ast_jb::impl, JB_CREATED, ast_jb::jbobj, ast_jb::logfile, ast_jb_impl::name, and ast_jb_impl::remove.

Referenced by ast_channel_destructor().

{
   struct ast_jb *jb = ast_channel_jb(chan);
   const struct ast_jb_impl *jbimpl = jb->impl;
   void *jbobj = jb->jbobj;
   struct ast_frame *f;

   if (jb->logfile) {
      fclose(jb->logfile);
      jb->logfile = NULL;
   }

   if (ast_test_flag(jb, JB_CREATED)) {
      /* Remove and free all frames still queued in jb */
      while (jbimpl->remove(jbobj, &f) == AST_JB_IMPL_OK) {
         ast_frfree(f);
      }

      jbimpl->destroy(jbobj);
      jb->jbobj = NULL;

      ast_clear_flag(jb, JB_CREATED);

      ast_verb(3, "%s jitterbuffer destroyed on channel %s\n", jbimpl->name, ast_channel_name(chan));
   }
}
int ast_jb_do_usecheck ( struct ast_channel c0,
struct ast_channel c1 
)

Checks the need of a jb use in a generic bridge.

Parameters:
c0first bridged channel.
c1second bridged channel.

Called from ast_generic_bridge() when two channels are entering in a bridge. The function checks the need of a jitterbuffer, depending on both channel's configuration and technology properties. As a result, this function sets appropriate internal jb flags to the channels, determining further behaviour of the bridged jitterbuffers.

Return values:
zeroif there are no jitter buffers in use
non-zeroif there are

Definition at line 161 of file abstract_jb.c.

References AST_CHAN_TP_CREATESJITTER, AST_CHAN_TP_WANTSJITTER, ast_channel_jb(), ast_channel_tech(), AST_JB_ENABLED, AST_JB_FORCED, ast_set_flag, ast_test_flag, ast_jb::conf, jb_choose_impl(), JB_CREATED, JB_TIMEBASE_INITIALIZED, JB_USE, ast_channel_tech::properties, and ast_jb::timebase.

Referenced by ast_generic_bridge().

{
   struct ast_jb *jb0 = ast_channel_jb(c0);
   struct ast_jb *jb1 = ast_channel_jb(c1);
   struct ast_jb_conf *conf0 = &jb0->conf;
   struct ast_jb_conf *conf1 = &jb1->conf;
   int c0_wants_jitter = ast_channel_tech(c0)->properties & AST_CHAN_TP_WANTSJITTER;
   int c0_creates_jitter = ast_channel_tech(c0)->properties & AST_CHAN_TP_CREATESJITTER;
   int c0_jb_enabled = ast_test_flag(conf0, AST_JB_ENABLED);
   int c0_force_jb = ast_test_flag(conf0, AST_JB_FORCED);
   int c0_jb_timebase_initialized = ast_test_flag(jb0, JB_TIMEBASE_INITIALIZED);
   int c0_jb_created = ast_test_flag(jb0, JB_CREATED);
   int c1_wants_jitter = ast_channel_tech(c1)->properties & AST_CHAN_TP_WANTSJITTER;
   int c1_creates_jitter = ast_channel_tech(c1)->properties & AST_CHAN_TP_CREATESJITTER;
   int c1_jb_enabled = ast_test_flag(conf1, AST_JB_ENABLED);
   int c1_force_jb = ast_test_flag(conf1, AST_JB_FORCED);
   int c1_jb_timebase_initialized = ast_test_flag(jb1, JB_TIMEBASE_INITIALIZED);
   int c1_jb_created = ast_test_flag(jb1, JB_CREATED);
   int inuse = 0;

   /* Determine whether audio going to c0 needs a jitter buffer */
   if (((!c0_wants_jitter && c1_creates_jitter) || (c0_force_jb && c1_creates_jitter)) && c0_jb_enabled) {
      ast_set_flag(jb0, JB_USE);
      if (!c0_jb_timebase_initialized) {
         if (c1_jb_timebase_initialized) {
            memcpy(&jb0->timebase, &jb1->timebase, sizeof(struct timeval));
         } else {
            gettimeofday(&jb0->timebase, NULL);
         }
         ast_set_flag(jb0, JB_TIMEBASE_INITIALIZED);
      }

      if (!c0_jb_created) {
         jb_choose_impl(c0);
      }

      inuse = 1;
   }

   /* Determine whether audio going to c1 needs a jitter buffer */
   if (((!c1_wants_jitter && c0_creates_jitter) || (c1_force_jb && c0_creates_jitter)) && c1_jb_enabled) {
      ast_set_flag(jb1, JB_USE);
      if (!c1_jb_timebase_initialized) {
         if (c0_jb_timebase_initialized) {
            memcpy(&jb1->timebase, &jb0->timebase, sizeof(struct timeval));
         } else {
            gettimeofday(&jb1->timebase, NULL);
         }
         ast_set_flag(jb1, JB_TIMEBASE_INITIALIZED);
      }

      if (!c1_jb_created) {
         jb_choose_impl(c1);
      }

      inuse = 1;
   }

   return inuse;
}
void ast_jb_empty_and_reset ( struct ast_channel c0,
struct ast_channel c1 
)

drops all frames from a jitterbuffer and resets it

Parameters:
c0one channel of a bridge
c1the other channel of the bridge

Definition at line 582 of file abstract_jb.c.

References ast_channel_jb(), ast_test_flag, ast_jb_impl::empty_and_reset, ast_jb::impl, JB_CREATED, JB_USE, and ast_jb::jbobj.

Referenced by ast_generic_bridge().

{
   struct ast_jb *jb0 = ast_channel_jb(c0);
   struct ast_jb *jb1 = ast_channel_jb(c1);
   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);
   }
}
void ast_jb_get_and_deliver ( struct ast_channel c0,
struct ast_channel c1 
)

Deliver the queued frames that should be delivered now for both channels.

Parameters:
c0first bridged channel.
c1second bridged channel.

Called from ast_generic_bridge() to deliver any frames, that should be delivered for the moment of invocation. Does nothing if neihter of the channels is using jb or has any frames currently queued in. The function delivers frames usig ast_write() each of the channels.

Definition at line 327 of file abstract_jb.c.

References ast_channel_jb(), ast_test_flag, JB_CREATED, jb_get_and_deliver(), and JB_USE.

Referenced by ast_generic_bridge().

{
   struct ast_jb *jb0 = ast_channel_jb(c0);
   struct ast_jb *jb1 = ast_channel_jb(c1);
   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)
      jb_get_and_deliver(c0);

   if (c1_use_jb && c1_jb_is_created)
      jb_get_and_deliver(c1);
}
void ast_jb_get_config ( const struct ast_channel chan,
struct ast_jb_conf conf 
)

Copies a channel's jitterbuffer configuration.

Parameters:
chanchannel.
confdestination.

Definition at line 577 of file abstract_jb.c.

References ast_channel_jb().

{
   memcpy(conf, &ast_channel_jb((struct ast_channel *) chan)->conf, sizeof(*conf));
}
struct ast_jb_impl* ast_jb_get_impl ( enum ast_jb_type  type) [read]

Definition at line 793 of file abstract_jb.c.

References ARRAY_LEN.

Referenced by jb_framedata_init().

{
   int i;
   for (i = 0; i < ARRAY_LEN(avail_impl); i++) {
      if (avail_impl[i].type == type) {
         return &avail_impl[i];
      }
   }
   return NULL;
}
int ast_jb_get_when_to_wakeup ( struct ast_channel c0,
struct ast_channel c1,
int  time_left 
)

Calculates the time, left to the closest delivery moment in a bridge.

Parameters:
c0first bridged channel.
c1second bridged channel.
time_leftbridge time limit, or -1 if not set.

Called from ast_generic_bridge() to determine the maximum time to wait for activity in ast_waitfor_n() call. If neihter of the channels is using jb, this function returns the time limit passed.

Returns:
maximum time to wait.

Definition at line 222 of file abstract_jb.c.

References ast_channel_jb(), ast_test_flag, get_now(), JB_CREATED, JB_USE, and ast_jb::next.

Referenced by ast_generic_bridge().

{
   struct ast_jb *jb0 = ast_channel_jb(c0);
   struct ast_jb *jb1 = ast_channel_jb(c1);
   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);
   int wait, wait0, wait1;
   struct timeval tv_now;

   if (time_left == 0) {
      /* No time left - the bridge will be retried */
      /* TODO: Test disable this */
      /*return 0;*/
   }

   if (time_left < 0) {
      time_left = INT_MAX;
   }

   gettimeofday(&tv_now, NULL);

   wait0 = (c0_use_jb && c0_jb_is_created) ? jb0->next - get_now(jb0, &tv_now) : time_left;
   wait1 = (c1_use_jb && c1_jb_is_created) ? jb1->next - get_now(jb1, &tv_now) : time_left;

   wait = wait0 < wait1 ? wait0 : wait1;
   wait = wait < time_left ? wait : time_left;

   if (wait == INT_MAX) {
      wait = -1;
   } else if (wait < 1) {
      /* don't let wait=0, because this can cause the pbx thread to loop without any sleeping at all */
      wait = 1;
   }

   return wait;
}
int ast_jb_put ( struct ast_channel chan,
struct ast_frame f 
)

Puts a frame into a channel jitterbuffer.

Parameters:
chanchannel.
fframe.

Called from ast_generic_bridge() to put a frame into a channel's jitterbuffer. The function will successfuly enqueue a frame if and only if: 1. the channel is using a jitterbuffer (as determined by ast_jb_do_usecheck()), 2. the frame's type is AST_FRAME_VOICE, 3. the frame has timing info set and has length >= 2 ms, 4. there is no some internal error happened (like failed memory allocation). Frames, successfuly queued, should be delivered by the channel's jitterbuffer, when their delivery time has came. Frames, not successfuly queued, should be delivered immediately. Dropped by the jb implementation frames are considered successfuly enqueued as far as they should not be delivered at all.

Return values:
0if the frame was queued
-1if not

Definition at line 262 of file abstract_jb.c.

References ast_channel_jb(), ast_channel_name(), ast_clear_flag, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frdup(), AST_FRFLAG_HAS_TIMING_INFO, ast_frfree, AST_JB_IMPL_OK, ast_log(), ast_set_flag, ast_test_flag, create_jb(), ast_jb_impl::force_resync, ast_frame::frametype, get_now(), ast_jb::impl, JB_CREATED, jb_framelog, JB_USE, ast_jb::jbobj, ast_frame::len, LOG_ERROR, LOG_WARNING, ast_jb_impl::next, ast_jb::next, ast_jb_impl::put, ast_frame::src, and ast_frame::ts.

Referenced by ast_generic_bridge().

{
   struct ast_jb *jb = ast_channel_jb(chan);
   const struct ast_jb_impl *jbimpl = jb->impl;
   void *jbobj = jb->jbobj;
   struct ast_frame *frr;
   long now = 0;

   if (!ast_test_flag(jb, JB_USE))
      return -1;

   if (f->frametype != AST_FRAME_VOICE) {
      if (f->frametype == AST_FRAME_DTMF && ast_test_flag(jb, JB_CREATED)) {
         jb_framelog("JB_PUT {now=%ld}: Received DTMF frame. Force resynching jb...\n", now);
         jbimpl->force_resync(jbobj);
      }

      return -1;
   }

   /* We consider an enabled jitterbuffer should receive frames with valid timing info. */
   if (!ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO) || f->len < 2 || f->ts < 0) {
      ast_log(LOG_WARNING, "%s received frame with invalid timing info: "
         "has_timing_info=%d, len=%ld, ts=%ld, src=%s\n",
         ast_channel_name(chan), ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO), f->len, f->ts, f->src);
      return -1;
   }

   frr = ast_frdup(f);

   if (!frr) {
      ast_log(LOG_ERROR, "Failed to isolate frame for the jitterbuffer on channel '%s'\n", ast_channel_name(chan));
      return -1;
   }

   if (!ast_test_flag(jb, JB_CREATED)) {
      if (create_jb(chan, frr)) {
         ast_frfree(frr);
         /* Disable the jitterbuffer */
         ast_clear_flag(jb, JB_USE);
         return -1;
      }

      ast_set_flag(jb, JB_CREATED);
      return 0;
   } else {
      now = get_now(jb, NULL);
      if (jbimpl->put(jbobj, frr, now) != AST_JB_IMPL_OK) {
         jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len);
         ast_frfree(frr);
         /*return -1;*/
         /* TODO: Check this fix - should return 0 here, because the dropped frame shouldn't
            be delivered at all */
         return 0;
      }

      jb->next = jbimpl->next(jbobj);

      jb_framelog("JB_PUT {now=%ld}: Queued frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len);

      return 0;
   }
}
int ast_jb_read_conf ( struct ast_jb_conf conf,
const char *  varname,
const char *  value 
)

Sets jitterbuffer configuration property.

Parameters:
confconfiguration to store the property in.
varnameproperty name.
valueproperty value.

Called from a channel driver to build a jitterbuffer configuration typically when reading a configuration file. It is not necessary for a channel driver to know each of the jb configuration property names. The jitterbuffer itself knows them. The channel driver can pass each config var it reads through this function. It will return 0 if the variable was consumed from the jb conf.

Returns:
zero if the property was set to the configuration, -1 if not.

Definition at line 532 of file abstract_jb.c.

References AST_JB_CONF_ENABLE, AST_JB_CONF_FORCE, AST_JB_CONF_IMPL, AST_JB_CONF_LOG, AST_JB_CONF_MAX_SIZE, AST_JB_CONF_PREFIX, AST_JB_CONF_RESYNCH_THRESHOLD, AST_JB_CONF_TARGET_EXTRA, AST_JB_ENABLED, AST_JB_FORCED, AST_JB_LOG, ast_set2_flag, ast_strlen_zero(), ast_true(), ast_jb_conf::impl, ast_jb_conf::max_size, name, ast_jb_conf::resync_threshold, and ast_jb_conf::target_extra.

Referenced by _build_general_config(), config_parse_variables(), gtalk_load_config(), jb_framedata_init(), jingle_load_config(), load_module(), process_dahdi(), reload_config(), and store_config_core().

{
   int prefixlen = sizeof(AST_JB_CONF_PREFIX) - 1;
   const char *name;
   int tmp;

   if (strncasecmp(AST_JB_CONF_PREFIX, varname, prefixlen)) {
      return -1;
   }

   name = varname + prefixlen;

   if (!strcasecmp(name, AST_JB_CONF_ENABLE)) {
      ast_set2_flag(conf, ast_true(value), AST_JB_ENABLED);
   } else if (!strcasecmp(name, AST_JB_CONF_FORCE)) {
      ast_set2_flag(conf, ast_true(value), AST_JB_FORCED);
   } else if (!strcasecmp(name, AST_JB_CONF_MAX_SIZE)) {
      if ((tmp = atoi(value)) > 0)
         conf->max_size = tmp;
   } else if (!strcasecmp(name, AST_JB_CONF_RESYNCH_THRESHOLD)) {
      if ((tmp = atoi(value)) > 0)
         conf->resync_threshold = tmp;
   } else if (!strcasecmp(name, AST_JB_CONF_IMPL)) {
      if (!ast_strlen_zero(value))
         snprintf(conf->impl, sizeof(conf->impl), "%s", value);
   } else if (!strcasecmp(name, AST_JB_CONF_TARGET_EXTRA)) {
      if (sscanf(value, "%30d", &tmp) == 1) {
         conf->target_extra = tmp;
      }
   } else if (!strcasecmp(name, AST_JB_CONF_LOG)) {
      ast_set2_flag(conf, ast_true(value), AST_JB_LOG);
   } else {
      return -1;
   }

   return 0;
}