PJSIP - Copy SIP Call-Info header on internal call

I have been trying for days to get the Call-Info header forwarded to an internal extension, when calling from another internal extension.
I need this for a Grandstream GDS3710 video door phone, which puts info in the Call-Info header, and that way the phones (GXP2140) know where to go fetch snapshots of the camera.
I am running Asterisk 15.7.3 and FreePBX, and I use PJSIP and that last part seems to be the tricky one.

I have tried numerous variations of exten => s,n,Set(Call-Info:${PJSIP_HEADER(read,Call-Info)}) under [macro-dialout-one-predial-hook] only to realize that this is probably never going to work because PJSIP doesn’t work that way.
When I to this, I see the correct message in my calling extension, but NOT in my called extension.

I browsed through the forum and found a few relevant posts, one of which more or less suggested to add this to extensions_custom.conf:
exten => s,1,noop(Adding custom header to PJSIP channel)
exten => s,n,Set(Call-Info:${PJSIP_HEADER(read,Call-Info)})
exten => s,n,Return

And adding Ttb(custom-header^s^1) to the extensions Asterisk Dial Options. However, still nothing.

Does anyone have a working config for this scenario? I can post some debug logs, but maybe someone has the solution right at hand…

Does it matter that the Set command doesn’t have an “=”?:
exten => s,n,Set(CI=${PJSIP_HEADER(read,Call-Info)})

If the channels are potentially changing, you could add __ to make the variable inherit:
exten => s,n,Set(__CI=${PJSIP_HEADER(read,Call-Info)})

I’ve not done this specifically, but if you see the correct header at one point during the call then you can for sure use it.

Thanks. Where would I have to put this? Under the [custom-header] field? And how do I call this then?

You can put it under any context you like, but you’d have to make sure you are hitting that context as part of you call treatment. I would add the set command into the treatment where you said you were already seeing the variable. It might work as you originally had it if you try the first suggestion. You’re going to have to try some of this out. But the answer is above, just got to make it fit.

Still no luck. I added
include => from-internal
exten => a,1,noop(Adding custom header to PJSIP channel)
exten => a,n,Set(__CI=${PJSIP_HEADER(read,Call-Info)})
extensions_custom.conf. I set the context for the relevant extensions to from-internal-custom, and that seems to work:
asterisk*CLI> dialplan show from-internal-custom
[ Context ‘from-internal-custom’ created by ‘pbx_config’ ]
‘a’ => 1. noop(Adding custom header to PJSIP channel) [extensions_custom.conf:6]
2. Set(__CI=${PJSIP_HEADER(read,Call-Info)}) [extensions_custom.conf:7]
Include => ‘from-internal’ [pbx_config]

However, I don’t see my command being called.
When I place a call, I see:
– Executing [[email protected]:1] GotoIf(“PJSIP/2007-00000163”, “1?ext-local,2008,1:followme-check,2008,1”) in new stack
– Goto (ext-local,2008,1)

And I also see this:
– Executing [[email protected]:54] Dial(“PJSIP/2007-00000163”, “PJSIP/2008/sip:[email protected]:39115,HhTtrb(func-apply-sipheaders^s^1)”) in new stack
– PJSIP/2008-00000164 Internal Gosub(func-apply-sipheaders,s,1) start
– Executing [[email protected]:1] NoOp(“PJSIP/2008-00000164”, “Applying SIP Headers to channel PJSIP/2008-00000164”) in new stack
– Executing [[email protected]:2] Set(“PJSIP/2008-00000164”, “TECH=PJSIP”) in new stack
– Executing [[email protected]:3] Set(“PJSIP/2008-00000164”, “SIPHEADERKEYS=”) in new stack
– Executing [[email protected]:4] While(“PJSIP/2008-00000164”, “0”) in new stack
– Jumping to priority 10
– Executing [[email protected]:11] Return(“PJSIP/2008-00000164”, “”) in new stack
== Spawn extension (from-internal-custom, 2008, 1) exited non-zero on ‘PJSIP/2008-00000164’
– PJSIP/2008-00000164 Internal Gosub(func-apply-sipheaders,s,1) complete GOSUB_RETVAL=

Yet, I don’t see the command I put in the config called. Am I missing something obvious here?

Assuming the a route is your issue. Since you are including the internal context, it is jumping to that, where it is finding 2008.

Hello @kellydk,

I just finished configuring a GDS3710 device to one of my clients and I think that you are going the complete wrong way in your integration (unless I am failing to understand you, and if so, please do not hesitate to correct me).

This is how you should configure your GXP2140 ip phone:

  1. Navigate to Settings → External Service and set the following:

  2. Set the Service Type to GDS.

  3. Select the related account, in our example, the account used is Account 1.

  4. Specifies the System Identification, to identify the GDS3710, in our example its “GDS3710_Front_Door”.

  5. Specifies the System Number which is the GDS3710 number, the system number used in our example is 2002.

  6. Configures the Access Password which is the “Remote PIN to Open the Door” configured on the GDS3710 Web GUI settings. The password used in our example is “123456”.

Note : The GXP21xx support up to 10 GDS3710 items

  1. Press the save and apply button to apply the new settings.

Once the user presses the ring button on the GDS3710, an INVITE will be sent to the GXP phone, and the GDS3710 stream will be played, allowing users to either answer / reject the call or press the OpenDoor softkey, then a DTMF code for “Remote PIN for Open the Door” will be sent to the GDS3710 in order to open the door remotely as displayed on the following screenshot:


Thank you,

Daniel Friedman
Trixton LTD.

1 Like

Hi Daniel,
That part (opening a door) is working fine. In fact, I don’t even think the GXP knows that this is a doorphone, it just recognizes the extension and then creates a softkey to send a few digits to the peer.

But how are you placing the call from 2002 to 2001? Does this pass over FreePBX? Or are you calling using the IP address of the destination phone? Because then it works fine…

@comtech: you lost me here. How can I get rid of that “a” then?

Hi @kellydk,

What is your purpose? to get a video call from your GXP2140? If yes, then configure the GDS3710 as an extension in the PBX and call it from your GXP2140 phone like I mentioned in my previous post. There is no meaning in just adding a Call-Info header with no info. You are confusing with opening a direct RTSP stream with a VLC player for example.

Make sure that the source extension is in the account settings white list tab on the GDS3710.

Thank you,

Daniel Friedman
Trixton LTD.

No, it’s the other way round. When someone rings the doorbell, I want the video (well, still images) to appear on the GXP2140 and that doesn’t work right now. The GXP2140 is not a videophone, but it can receive still images from the GDS3710. It does that by grabbing images on the webserver of the GDS, and the Call Info field in the SIP header contains the URL to use. But FreePBX does not relay that header.

You’re saying it works out of the box for you. Are you using CHAN_SIP or PJSIP?

You would need to reference the 2008 extension or a proxy for it.


Hello @kellydk,

Assuming that extension 2008 is the GDS3710 and extension 2007 is the GXP2140, add this dialplan to your extensions_custom.conf file. Please delete everything that you have in the from-internal-custom context before applying my dialplan:

;Adding a Call-Info header to the channel when someone press the button on the GDS3710
;2008 - GDS3710
;2007 - GXP2140
;The Call-Info header would be added to the channel only If the GDS3710 will call to extension 2007

exten => 2007/2008,1,Log(NOTICE,GDS3710 is calling to extension ${EXTEN})
same => n,GoSub(func-set-sipheader,s,1(Call-Info,<http://the_ip_address_of_the_GDS3710>))

Change the dialplan according to your network If I confused the extension numbers, and add the GDS3710 ip address to the dialplan.
Do not forget to reload the dialplan after any change in the extensions_custom.conf file like that:

dialplan reload from the Asterisk console
rasterisk -x'dialplan reload' from the Linux console.

Thank you,

Daniel Friedman
Trixton LTD.

1 Like

That seems to do the trick!

I modified it slightly to:

include => from-internal
exten => 2007/2008,1,Log(NOTICE,GDS3710 is calling to extension ${EXTEN})
same => n,GoSub(func-set-sipheader,s,1(Call-Info,<IP_of_GDS3710:443/capture/8001> ;purpose=GDS-view))

IP is prefixed by https:// , I can’t put a link in a post apparently

As this is the information the GDS3710 passes on to FreePBX. I can’t test it right now as I don’t have GXP2140’s here, but the debug and packet capture look promising. I’ll let you know on Friday if it actually works.


Hello @kellydk,

I am glad that this solves your problem, but please do not include the from-internal context in the from-internal-custom context. It is already included and it might cause a loop.

Another thing, you will have to escape the semi-colon in your Call-Info link.

It should look like this:

exten => 2007/2008,1,Log(NOTICE,GDS3710 is calling to extension ${EXTEN})
same => n,GoSub(func-set-sipheader,s,1(Call-Info,<https://IP_of_GDS3710:443/capture/8001>\;purpose=GDS-view))

Thank you,

Daniel Friedman
Trixton LTD.

1 Like

I have to disagree, unfortunately :slight_smile:

When I do NOT put include => from-internal in the [from-internal-custom] context, all other calls fail with 404 not found.
Haven’t debugged any further, it works fine now. Thanks again!

Hello @tuffcalc,

Good to hear that it works fine with you, and that you can see the video on your ip phones when the GDS 3710 rings your ip phones.

Please be aware, that your from-internal-custom may cause you loops in your dialplan if you will not remove the include of the from-internal context. The way that Asterisk parsing the dial plan, is to include the other contexts at the end of the context execution. It would be best if you could debug your dialplan without the including of the from-internal context, and share your logs here.

Thank you,

Daniel Friedman
Trixton LTD.

This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.