PJSIP Jitter Buffer

I don’t think I can, I am not a big supporter of chan-pjsip for trunking , and good old chan-sip is well documented as to jitter buffers.

Thanks anyway. Hopefully someone else here can help.

Though do note it’s for an endpoint, not a trunk. My trunks are set up with chan_sip. Only endpoints use chan_pjsip.

The set the jitter buffer on the chan_sip leg.

I actually did do that last night, but it doesn’t seem to have helped.

Which makes sense that it didn’t help, because AFAIK, the jitter buffer sits before the Asterisk core and buffers/reorders packets before they are transmitted to the Asterisk core, so it works on input into Asterisk. The jitter buffer on my trunks would fix jitter coming into Asterisk from the trunks, but that’s not a factor because the Asterisk box is hosted in a Chicago Loop datacenter with stable latency to pretty much anywhere on the continent. AFAICT, a jitter buffer doesn’t do anything for audio coming out of Asterisk, so having it on chan_sip (where my trunks lie) won’t do anything.

I guess I’ll have to try to hunt down and understand how contexts and dialplans in extensions_custom.conf work to figure out how to integrate what user @cw89 and you were talking about upthread…well, at least this’ll be educational, if a bit painful…any advice on how to look into that would be appreciated. :slight_smile:

(Worst comes to worst, I can re-set-up this particular extension as a chan_sip extension instead of a chan_pjsip extension, but I’d prefer not to for now.)

One thing that I think would help me go a long way is understanding what you meant by this, @dicko:

Not quitye you will need to add a context , something like

What does that + sign do when defining a context?

I also have entries like this in some other _custom.conf files:



What does the + and the (+) do in the FreePBX world of _custom.conf files? I can find zero documentation of that anywhere and it’s difficult to Google because Google of course does not support special characters…

A jitter buffer is just in effect a fifo which reorders packets and replaces missing ones it’s good for two or three packets without being too noticable if you force it to be longer, perhaps you get less replaced/out of order packets, but the increased audio delay is generally self defeating , it really doesn’t matter where in the signal path it is though,(well , at least between your network and yoyr handset)


is just what you think but badly formatted

So anyone get this actually working?

Let’s say I have a WiFi phone on iLBC or anything other than G.711 (which has zero packet loss / error correction), and my trunk only supports G.711 but the connection to the trunk is stable.

It would make sense to add a jitter buffer from the WiFi phone to the PBX but I don’t seem to be able to on the receive side of things. I tried exten => 1,1,Set(JITTERBUFFER(fixed)=2000) in /etc/asterisk/extensions_custom.conf, just to test I know not to have a JB of that size, but nothing seems to happen.

Bump, anyone? Would really improve our call qualify out in the field!!!


I don’t really speak PJ-SIP, so I can only offer one insight. A 2000 mSec Jitter buffer means that you will have a 2-second delay on your inbound and outbound traffic. I’m not sure I understand how that improves your call quality.

Also, it sound like you are thinking in terms of traditional telephony, which Asterisk is not. Your connection from the phone to the server is separate and distinct from your connect to the trunk. The Asterisk server sits between them, managing the traffic and transcoding (if required) the audio from one end device to the other. Because of that, your concerns about the trunk’s configuration and the phone’s line configuration aren’t really pertinent to your issue.

Finally, there are some things about your approach that need help.

  1. Your code snippet needs a context - you need to make sure that the code is getting executed as part of your normal call process. Without the context information, there’s no way that the snippet will ever be executed.
  2. Your code snippet refers to extension 1 in the code (the first ‘1’ in the ‘1,1,…’ line). This means that, even the context is being correctly processed, it will only effect extension ‘1’. Having an extension ‘1’ is always a bad idea.
  3. If there is already an extension ‘1,1,…’ step in one of your contexts, this code will never be executed because the line will already be defined and the system doesn’t allow you to redefine context steps that have already been established.

Hi Cynjut,

I do realize 2,000ms jitter buffer would be insane but as I said its just to test if it works, as I haven’t been able to get it working. I’m not sure which context to use. The jitter buffer should be for the extension specified but it doesn’t appear to be added. I only see it in the logs on asterisk’s start not when calls are incoming or outgoing.

Here is my complete extensions_custom.conf

; PJSIP Jitter Buffer
exten => 1004,1,Set(JITTERBUFFER(fixed)=200,1000)

exten => 1004,1,Set(JITTERBUFFER(fixed)=200,1000)

exten => 1004,1,Set(JITTERBUFFER(fixed)=200,1000)

Note to the true professional context writers - I understand that this is not the “by the book” explanation, but it is how I explain it to new people, so as long as it’s mostly OK (at least from the theory perspective), let’s not get caught up in the details.

First, it helps to broadly think of contexts like you would any other program subroutine - If it already exists, adding another one with the same name and arguments is an error. That’s kind of what you are doing here. You are also adding steps that already exist, and those can’t happen either.

Little known fact about writing Asterisk context rules:

A context can be defined once (like [from-internal] and cannot be redefined. As such, you can’t create new contexts with old names in the “*-custom” configuration files. You can, however, extend them using the “(+)” operator. This allows you to add more stuff to an existing context.

Within a context, each rules has three parts:

  1. The extension number (1004 in your case).
  2. The Priority (1 in your case)
  3. The Action (or payload, or whatever…).

So, your contexts are probably being ignored since they are already defined. Adding the “(+)” operator to them (i.e., “[from-internal] (+)” ) will extend them, but (here’s the other tricky part), if you already have an extension ‘1004’ instantiated and it already has a priority ‘1’, you can’t add that new context rule because it already exists.

From experience, I’d think you’d want to try using “s,n,Set…” instead of the way you are doing it now. That way, whenever you instantiate “[from-internal]”, the ‘start’ action will include the stuff that’s already in there, plus the new 'n’ext step that you are adding in your “extended” code.

To fix this, you would normally either add your code to a segment that’s there specifically to add extension settings (there are some, I just don’t do custom context work enough to be able to suggest any off the top of my head). What you are doing now is trying to add them to calls, which should actually work (once the syntax is all correct). Remember, “from-internal” is the context your phones “call”, so adding this code to that should mean that whenever you place a call (even to voicemail or between extensions) you will be adding jitter buffering.

If your inbound routes use “from-external”, then adding the buffer there will add it to every call that comes from the outside. I’m pretty sure “default” is only used when picking up voicemail, if at all, so you should be able to dump that.

Note that working at this level is 7th level mage stuff, so it might pay for you to look around and see if you can get a little more experience before you dive much deeper.

So I did change the contexts to have (+) now and added n instead of 1 to the priority but doesn’t seem to make the slightest difference.

> [[email protected] ~]# cat /var/log/asterisk/full | grep -i "jitter"
> [2018-04-13 13:20:21] VERBOSE[1362] loader.c: Loading func_jitterbuffer.so.
> [2018-04-13 13:20:21] VERBOSE[1362] pbx_functions.c: Registered custom function 'JITTERBUFFER'
> [2018-04-13 13:20:21] VERBOSE[1362] loader.c: func_jitterbuffer.so => (Jitter buffer for read side of channel.)

I only see the above when starting asterisk, nothing more and there is clearly no delay.

You need to put this into macro-dial and macro-dial-one. Your placement currently does nothing

@expresspotato , IMO it’s unlikely that a jitter buffer will fix your problem. There is likely very little jitter coming from the trunk, so the buffer could only help outbound audio quality from the Wi-Fi phone; what the Wi-Fi user hears would not be improved.

Most Wi-Fi issues (interference from other users on the network or from other networks sharing the channel, device periodically switching off channel to look for a stronger AP, etc.) would affect both directions equally.

I suppose it’s possible that if the signal is simply too weak, outbound could be worse than inbound if the AP’s TX power is much greater than the phone’s. But in that case, it’s likely that you also have significant packet loss, which a buffer obviously can’t cure.

Do you have any credible evidence that a buffer would be helpful?

1 Like

I mean it should, its not only really the WiFi receiving client that I’m worried about, its more the client that ends up receiving the call. Clients complain the person on the other end if breaking up hence the need for a receive jitter buffer.

We’re trying to achieve google voice like quality and in 2018 it shouldn’t be so hard :frowning:

exten => 1004,1,Set(JITTERBUFFER(fixed)=2000)

exten => 1004,1,Set(JITTERBUFFER(fixed)=2000)

Still nothing…

You did it wrong. Please look at how macro-dial and macro-dial-one are generated before blindly destroying dialplan with random extensions (1004) and priorities (1).

So you want unreliable voice? (Sorry couldn’t resist)

1 Like

Well I mean callsetup or not but this and facebook messenger have vastly superior call qualify over wifi / celullar types of networks.

When you need to inject your own dialplan into a normal call flow, you first look for dialplan hooks. Suppose you have a normal local extension with with no CF or FMFM enabled. When I dial from 5014 to the extension in question I see an Asterisk log line like this:

[[email protected] asterisk]# tail -f full | grep hook
[2018-04-13 17:12:59] VERBOSE[26548][C-00000000] pbx.c: Executing [[email protected]:52] Macro("SIP/5014-00000000", "dialout-one-predial-hook,") in new stack
[2018-04-13 17:12:59] VERBOSE[26548][C-00000000] pbx.c: Executing [[email protected]:1] MacroExit("SIP/5014-00000000", "") in new stack

Well howdy, ain’t that nice. The developers have left a hook for me to use, must remember to send them a Christmas card. All I have to do is to populate the macro with something like this in extensions_custom.conf:

exten => s,1,Noop(Entering user defined context in extensions_custom.conf)
exten => s,n,MacroExit

Save the file, reload the dialplan and the next time I call my local extension I get something new and exiting.

[[email protected] asterisk]# tail -f full | grep hook
[2018-04-13 17:16:50] VERBOSE[27306][C-00000001] pbx.c: Executing [[email protected]:52] Macro("SIP/5014-00000002", "dialout-one-predial-hook,") in new stack
[2018-04-13 17:16:50] VERBOSE[27306][C-00000001] pbx.c: Executing [[email protected]:1] NoOp("SIP/5014-00000002", "Entering user defined context in extensions_custom.conf") in new stack
[2018-04-13 17:16:50] VERBOSE[27306][C-00000001] pbx.c: Executing [[email protected]:2] MacroExit("SIP/5014-00000002", "") in new stack

My custom code has been ‘hooked’ and now runs every time I call a local extension.

There are several hooks so depending on whether you are using ring groups or FMFM or some other ring strategy, you might use a different hook, but the technique above works for them all.

Thanks, and I did see that but:

[[email protected] ~]# asterisk -rx "dialplan reload" && asterisk -rx "dialplan show macro-dialout-one-predial-hook"
Dialplan reloaded.
[ Context 'macro-dialout-one-predial-hook' created by 'pbx_config' ]
  's' =>            1. Verbose(2, Test the hook)                  [pbx_config]

-= 1 extension (1 priority) in 1 context. =-
[[email protected] ~]# tail -n5000 /var/log/asterisk/full| grep -i "Test the hook"

exten=>1004,1,Verbose(2, Test the hook)
[[email protected] ~]# asterisk -rx "dialplan reload" && asterisk -rx "dialplan show macro-dialout-one-predial-hook"
Dialplan reloaded.
[ Context 'macro-dialout-one-predial-hook' created by 'pbx_config' ]
  '1004' =>         1. Verbose(2, Test the hook)                  [pbx_config]
  's' =>            1. MacroExit()                                [pbx_config]

-= 2 extensions (2 priorities) in 1 context. =-
[[email protected] ~]# tail -n5000 /var/log/asterisk/full| grep -i "Test the hook"

Doesn’t seem like the hook is even being called?

[[email protected] ~]# tail -n5000 /var/log/asterisk/full| grep -i "hook"
[2018-04-13 17:17:51] VERBOSE[7943][C-0000001c] pbx.c: Executing [[email protected]:17] Set("PJSIP/1004-0000001e", "AUDIOHOOK_INHERIT(MixMonitor)=yes") in new stack
[2018-04-13 17:17:51] VERBOSE[7943][C-0000001c] pbx.c: Executing [[email protected]:18] Macro("PJSIP/1004-0000001e", "dialout-trunk-predial-hook,") in new stack
[2018-04-13 17:17:51] VERBOSE[7943][C-0000001c] pbx.c: Executing [[email protected]:1] MacroExit("PJSIP/1004-0000001e", "") in new stack