Skip to content

Instantly share code, notes, and snippets.

@zaxbux
Last active August 26, 2022 03:21
Show Gist options
  • Save zaxbux/ed2ce3926311c39c95286e5f56f71aad to your computer and use it in GitHub Desktop.
Save zaxbux/ed2ce3926311c39c95286e5f56f71aad to your computer and use it in GitHub Desktop.
Grandstream GRP26xx SIP Integration

Integrating a Grandstream GRP26xx series IP Phone with FreePBX/Asterisk

Resources:

Grandstream-specific features

Call Recording

To get the "Record On/Off" soft keys to appear on the phone, a special X-UCM-AudioRecord header must be sent in the SIP INVITE to the phone:

X-UCM-AudioRecord: *1

Call Parking

To get the "Park" soft key to appear on the phone, a special X-UCM-CallPark header must be sent in the SIP INVITE to the phone:

X-UCM-CallPark: *88

Adding SIP INVITE Headers in Asterisk

Add this to extensions_custom.conf (FreePBX) for PJSIP:

; Dialing an extension
[macro-dialout-one-predial-hook]
exten => s,1,Set(HASH(__SIPHEADERS,X-UCM-AudioRecord)=*1)
exten => s,n,MacroExit()

; Dialing from a ringall group
[macro-dial-ringall-predial-hook]
exten => s,1,Set(HASH(__SIPHEADERS,X-UCM-AudioRecord)=*1)
exten => s,n,MacroExit()

; Dialing from a hunt group
[macro-dial-hunt-predial-hook]
exten => s,1,Set(HASH(__SIPHEADERS,X-UCM-AudioRecord)=*1)
exten => s,n,MacroExit()

chan_sip example:

[macro-dialout-one-predial-hook]
exten => s,1,SIPAddHeader(X-UCM-AudioRecord: *1)
exten => s,n,MacroExit()

PJSIP Presence Events

VPK Type that is interesting: "Presence Eventlist" (accepts )

(https://wiki.asterisk.org/wiki/display/AST/Configuring+res_pjsip+for+Presence+Subscriptions)

Add asterisk modules:

  • res_pjsip.so
  • res_pjsip_pubsub.so
  • res_pjsip_exten_state.so
  • res_pjsip_pidf_body_generator.so
  • res_pjsip_dialog_info_body_generator.so

GRP26xx

  • Phone sends SIP SUBSCRIBE to configured Presence Eventlist URI
    • Accept: application/pidf+xml
    • Event: presence
    • Supported: eventlist
  • VPK in Presence Eventlist mode configures
NOTIFY sip:2000@[2001:569:bda5:8c02:c274:adff:fe0a:9e7b]:42332;transport=TLS SIP/2.0
Via: SIP/2.0/TLS [2001:569:bda5:8c02:7a8a:20ff:fe7f:ddeb]:5061;rport;branch=z9hG4bKPj6c15ab8c-adee-436e-bcca-94b99981ebdb;alias
From: <sip:presence@pbx>;tag=85287ce3-420a-4c41-b660-bd18d84846c9
To: <sip:2000@pbx>;tag=2060185054
Contact: <sip:[2001:569:bda5:8c02:7a8a:20ff:fe7f:ddeb]:5061;transport=TLS>
Call-ID: 1139765237-34728-4@CAAB:FGJ:bdaF:IcAC:cCHE:adff:feAa:JeHb
CSeq: 11387 NOTIFY
Event: presence
Subscription-State: active;expires=3599
Allow-Events: message-summary, presence, dialog, refer
Require: eventlist
Max-Forwards: 70
User-Agent: FPBX-15.0.17.24(16.15.1)
Content-Type: multipart/related;type="application/rlmi+xml";boundary=pvkcb
Content-Length: 1147
--pvkcb
Content-ID: <uetht@2001:569:bda5:8c02:7a8a:20ff:fe7f:ddeb>
Content-Type: application/rlmi+xml
Content-Length: 433
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns="urn:ietf:params:xml:ns:rlmi" uri="sip:presence@[2001:569:bda5:8c02:7a8a:20ff:fe7f:ddeb]:5061;transport=TLS" version="0" fullState="true">
<name>presence</name>
<resource uri="sip:2000@[2001:569:bda5:8c02:7a8a:20ff:fe7f:ddeb]:5061;transport=TLS">
<name>2000</name>
<instance id="rewue" state="active" cid="omddx@2001:569:bda5:8c02:7a8a:20ff:fe7f:ddeb" />
</resource>
</list>
--pvkcb
Content-ID: <omddx@2001:569:bda5:8c02:7a8a:20ff:fe7f:ddeb>
Content-Type: application/pidf+xml
Content-Length: 437
<?xml version="1.0" encoding="UTF-8"?>
<presence entity="sip:2000@[2001:569:bda5:8c02:7a8a:20ff:fe7f:ddeb]:5061;transport=TLS" xmlns="urn:ietf:params:xml:ns:pidf" xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:rpid="urn:ietf:params:xml:ns:pidf:rpid">
<note>Unavailable</note>
<tuple id="2000">
<status>
<basic>closed</basic>
</status>
<contact priority="1">sip:2000@pbx</contact>
</tuple>
<dm:person />
</presence>
--pvkcb--
/*! \brief Add "X-UCM-AudioRecord" header and "X-UCM-CallPark" header to outgoing message
*
* if the right is allow callee or allow both, add the header in Invite message;
if the right is allow caller or allow both, add the header in 200 for Invite message
*
* \param req The request/response to which we will add the header
*/
void add_feature_map_header(pjsip_tx_data *tdata, int outgoing_call)
{
char audio_record_code[12] = {0};
char call_park_code[12] = {0};
if (NULL == tdata) {
return;
}
/* check right */
if (outgoing_call == 0) {
/* copy code */
if (0 != (gs_feature_map[GS_FEATURE_AUTOMIXMON].f_right & GS_FEATURE_ALLOW_CALLER)) {
strncpy(audio_record_code, gs_feature_map[GS_FEATURE_AUTOMIXMON].f_code, sizeof(audio_record_code));
}
if (0 != (gs_feature_map[GS_FEATURE_PARKCALL].f_right & GS_FEATURE_ALLOW_CALLER)) {
strncpy(call_park_code, gs_feature_map[GS_FEATURE_PARKCALL].f_code, sizeof(call_park_code));
}
}
else {
if (0 != (gs_feature_map[GS_FEATURE_AUTOMIXMON].f_right & GS_FEATURE_ALLOW_CALLEE)) {
strncpy(audio_record_code, gs_feature_map[GS_FEATURE_AUTOMIXMON].f_code, sizeof(audio_record_code));
}
if (0 != (gs_feature_map[GS_FEATURE_PARKCALL].f_right & GS_FEATURE_ALLOW_CALLEE)) {
strncpy(call_park_code, gs_feature_map[GS_FEATURE_PARKCALL].f_code, sizeof(call_park_code));
}
}
/* add header */
if (strlen(audio_record_code) > 0) {
ast_sip_add_header(tdata, "X-UCM-AudioRecord", audio_record_code);
}
if (strlen(call_park_code) > 0) {
ast_sip_add_header(tdata, "X-UCM-CallPark", call_park_code);
}
return;
}
/*
* Comment: Should grab feature codes from the `[featuremap]` section in `features.conf`.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment