SIPAddHeader() vs PJSIP_HEADER(add...)

I’m converting my naked asterisk 18.1 box to PJSIP.

In the good old days, I used SIPAddHeader(foo: bar) on incoming channels to change the behavior of my Polycom phones (distinctive ring, autoanswer, etc). My attempt at translation is Set(PJSIP_HEADER(add,foo)=bar), but it isn’t working. Tcpdump assures me foo: bar is never uttered by the new box.

Is it because I can “[only] read specific SIP headers from the inbound PJSIP channel” and “write (add, update, remove) headers on the outbound channel”? Are incoming headers are now immutable? Is there a better way to achieve the same effect?

Thanks for any input.

They work fundamentally differently, and as you’ve stated if you set PJSIP_HEADER then the header is set on THAT channel and not on any outbound channels. The wiki has an example for this[1] in the " Set headers on callee channel" section.

To also be specific, you were never changing or altering incoming headers in chan_sip. You were adding a new header, and because it predated pre-dial functionality it had to be implemented the way it was - where you set it on the incoming channel and then it got inherited to the outgoing channel.

[1] Asterisk 19 Function_PJSIP_HEADER - Asterisk Project - Asterisk Project Wiki

You could always look at the FreePBX code (or most of the call traces on their forum), as setting Alert-Info is one of their standard features.

I’m stupid! I read, “If you call PJSIP_HEADER in a normal dialplan context you’ll be operating on the caller’s (incoming) channel which may not be what you want” and thought “That’s exactly what I want” and stopped reading.

Chan_sip (and me not thinking about this stuff for 10 years, or pumphead, or something) made me forget about the outgoing channel. On a bicycle ride I realized that’s exactly what I was sniffing with tcpdump. I fully understand why you’re to replacing it with chan_pjsip. I don’t understand either one, but I see some glimmer of hope for PJSIP.

So back to your referenced page. I understand it down to the b(handler^addheader^1. I’m guessing ^ isn’t xor, but some sort of separator and the argument specifies the context, exten name, and priority, right? But what’s this function b() mentioned there?

Never mind. I found Pre-dial handlers Specification, and learned all about b() and B(). I wish I’d been sitting in on that syntax meeting. I’d have come armed with a pie!

Hopefully, this is my last shred of stupidity. But I still have to revise my Fast_AGI handler; I’m sure I’ll be back.

I got this working:

exten => addhdr,1,Set(PJSIP_HEADER(add,${ARG1})=${ARG2})
same  => n,Return()

Without the second line, it worked, but I heard whining:

Abnormal 'Gosub(local,addhdr,1(Foo,bar))' exit.  Popping routine return locations.

Should I take a run at the wiki?

You generally want to call Return(). It’s part of subroutines, ala Gosub.

We typically like forcing Caller ID to get set by whatever is configured for the extension but have some downstream systems where we wish to pass customer overriding Caller ID through. On those systems we set the desired Caller ID as a custom SIP / IAX header (X-CallerID) on the down stream system and then use that when placing the outgoing call on the upstream host.

NB: We prefer configuring trunks as standard extensions as it makes configuring failover routing flexible. We for example have our Microsoft Teams tenant connected to our Asterisk box and subsequently configure follow me on the main extension to ring both the standard VoIP handset as well as Teams when dialled.

On the downstream system (FreePBX 16 with Asterisk 18 but has worked like this since Asterisk 1.6):
Each extension has a DID from various ranges where the last 4 digits of the DID is the extension number. We also have Microsoft Teams integrated as well but that passes the Caller ID as the full DID, for example:
3055 → 0115553055
0108 → 0116660108

exten => s,1,ExecIf($[${REGEX("^30[0-9][0-9]$" ${CALLERID(num)})}]?Set(CALLERID(num)=011555${CALLERID(num)}))
exten => s,n,ExecIf($[${REGEX("^0[12][0-9][0-9]$" ${CALLERID(num)})}]?Set(CALLERID(num)=011666${CALLERID(num)}))
exten => s,n,GotoIf($[${REGEX("^[\+]271155530[0-9][0-9]$" ${CALLERIDNUMINTERNAL})}]?teams)
exten => s,n,GotoIf($[${REGEX("^[\+]27116660[12][0-9][0-9]$" ${CALLERIDNUMINTERNAL})}]?teams)
exten => s,n,Goto(tech)
exten => s,n(teams),Set(AMPUSERCID=${CALLERIDNUMINTERNAL:8})
exten => s,n(tech),Set(TECH=${CUT(custom,/,1)})
exten => s,n,GotoIf($["${TECH}" = "SIP"]?sip)
exten => s,n,GotoIf($["${TECH}" = "PJSIP"]?pjsip)
exten => s,n,GotoIf($["${TECH}" = "IAX2"]?iax2)
exten => s,n,Goto(finish)
exten => s,n(sip),SIPAddHeader(X-CallerID:${CALLERID(name)} <${CALLERID(num)}>)
exten => s,n,Goto(finish)
exten => s,n(pjsip),Set(HASH(__SIPHEADERS,X-CallerID)=${CALLERID(name)} <${CALLERID(num)}>)
exten => s,n,Goto(finish)
exten => s,n(iax2),Set(IAXVAR(X-CallerID)=${CALLERID(name)} <${CALLERID(num)}>)
exten => s,n(finish),MacroExit

The upstream system then checks for these headers and sets the Caller ID as required:

exten => s,1,Set(TECH=${CUT(CHANNEL,/,1)})
exten => s,n,GotoIf($["${TECH}" = "SIP"]?sip)
exten => s,n,GotoIf($["${TECH}" = "PJSIP"]?pjsip)
exten => s,n,GotoIf($["${TECH}" = "IAX2"]?iax2)
exten => s,n,Goto(next)
exten => s,n(sip),ExecIf($[ ${LEN(${SIP_HEADER(X-CallerID)})} > 0 ]?Set(CALLERID(all)=${SIP_HEADER(X-CallerID)}))
exten => s,n,SIPRemoveHeader(X-CallerID:)
exten => s,n,Goto(next)
exten => s,n(pjsip),ExecIf($[ ${LEN(${PJSIP_HEADER(read,X-CallerID)})} > 0 ]?Set(CALLERID(all)=${PJSIP_HEADER(read,X-CallerID)}))
exten => s,n,Set(PJSIP_HEADER(remove,X-CallerID)=)
exten => s,n,Goto(next)
exten => s,n(iax2),ExecIf($[ ${LEN(${IAXVAR(X-CallerID)})} > 0 ]?Set(CALLERID(all)=${IAXVAR(X-CallerID)}))
exten => s,n,Set(IAXVAR(X-CallerID)=)
exten => s,n(next),ExecIf($[${REGEX("<0" ${CALLERID(all)})}]?Set(CALLERID(all)=${STRREPLACE(CALLERID(all),<0,<+27)}))

Use it or lose it, hope it helps…

I have to this for Jitsi since Jigasi wants the confrerence room name in a SIP header.

exten = afterdark,1,Dial(PJSIP/jitsi,,b(lidnetjitsi^addheader^1))

exten = 98003,1,Answer
same = n,GoToIf($["${DB_EXISTS(lidnet/afterdark)}" = "1"]?internal,afterdark,1)
same = n,Playback(astjuke/red)
same = n,Hangup()

exten = addheader,1,Set(PJSIP_HEADER(add,Jitsi-Conference-Room)=afterdark)

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