diff options
-rw-r--r-- | channels/chan_h323.c | 63 | ||||
-rw-r--r-- | channels/h323/ast_h323.cxx | 123 | ||||
-rw-r--r-- | channels/h323/ast_h323.h | 2 | ||||
-rw-r--r-- | channels/h323/caps_h323.cxx | 13 | ||||
-rw-r--r-- | channels/h323/chan_h323.h | 8 | ||||
-rw-r--r-- | configs/h323.conf.sample | 4 |
6 files changed, 153 insertions, 60 deletions
diff --git a/channels/chan_h323.c b/channels/chan_h323.c index ee2ded742..607de74e3 100644 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -184,7 +184,7 @@ struct oh323_pvt { int peercapability; /* Capabilities learned from peer */ int jointcapability; /* Common capabilities for local and remote side */ struct ast_codec_pref peer_prefs; /* Preferenced list of codecs which remote side supports */ - int dtmf_pt; /* Payload code used for RFC2833 messages */ + int dtmf_pt[2]; /* Payload code used for RFC2833/CISCO messages */ int curDTMF; /* DTMF tone being generated to Asterisk side */ int DTMFsched; /* Scheduler descriptor for DTMF */ int update_rtp_info; /* Configuration of fd's array is pending */ @@ -515,7 +515,9 @@ static int oh323_digit_begin(struct ast_channel *c, char digit) return -1; } ast_mutex_lock(&pvt->lock); - if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) { + if (pvt->rtp && + (((pvt->options.dtmfmode & H323_DTMF_RFC2833) && pvt->dtmf_pt[0]) + /*|| ((pvt->options.dtmfmode & H323_DTMF_CISCO) && pvt->dtmf_pt[1]))*/)) { /* out-of-band DTMF */ if (h323debug) { ast_log(LOG_DTMF, "Begin sending out-of-band digit %c on %s\n", digit, c->name); @@ -554,7 +556,7 @@ static int oh323_digit_end(struct ast_channel *c, char digit) return -1; } ast_mutex_lock(&pvt->lock); - if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) { + if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && ((pvt->dtmf_pt[0] > 0) || (pvt->dtmf_pt[0] > 0))) { /* out-of-band DTMF */ if (h323debug) { ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s\n", digit, c->name); @@ -644,7 +646,7 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout) pvt->outgoing = 1; if (h323debug) - ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec); + ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d/%d\n", called_addr, pvt->options.dtmfcodec[0], pvt->options.dtmfcodec[1]); ast_mutex_unlock(&pvt->lock); res = h323_make_call(called_addr, &(pvt->cd), &pvt->options); if (res) { @@ -757,7 +759,7 @@ static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt) f = ast_rtp_read(pvt->rtp); /* Don't send RFC2833 if we're not supposed to */ - if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & H323_DTMF_RFC2833)) { + if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & (H323_DTMF_RFC2833 | H323_DTMF_CISCO))) { return &ast_null_frame; } if (pvt->owner) { @@ -979,8 +981,10 @@ static int __oh323_rtp_create(struct oh323_pvt *pvt) ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat); ast_rtp_setnat(pvt->rtp, pvt->options.nat); - if (pvt->dtmf_pt > 0) - ast_rtp_set_rtpmap_type(pvt->rtp, pvt->dtmf_pt, "audio", "telephone-event", 0); + if (pvt->dtmf_pt[0] > 0) + ast_rtp_set_rtpmap_type(pvt->rtp, pvt->dtmf_pt[0], "audio", "telephone-event", 0); + if (pvt->dtmf_pt[1] > 0) + ast_rtp_set_rtpmap_type(pvt->rtp, pvt->dtmf_pt[1], "audio", "cisco-telephone-event", 0); if (pvt->peercapability) ast_rtp_codec_setpref(pvt->rtp, &pvt->peer_prefs); @@ -1121,7 +1125,7 @@ static struct oh323_pvt *oh323_alloc(int callid) } memcpy(&pvt->options, &global_options, sizeof(pvt->options)); pvt->jointcapability = pvt->options.capability; - if (pvt->options.dtmfmode & H323_DTMF_RFC2833) { + if (pvt->options.dtmfmode & (H323_DTMF_RFC2833 | H323_DTMF_CISCO)) { pvt->nonCodecCapability |= AST_RTP_DTMF; } else { pvt->nonCodecCapability &= ~AST_RTP_DTMF; @@ -1263,18 +1267,28 @@ static int update_common_options(struct ast_variable *v, struct call_options *op options->dtmfmode |= H323_DTMF_INBAND; } else if (!strcasecmp(val, "rfc2833")) { options->dtmfmode |= H323_DTMF_RFC2833; - if (!opt) - options->dtmfcodec = H323_DTMF_RFC2833_PT; - else if ((tmp >= 96) && (tmp < 128)) - options->dtmfcodec = tmp; - else { - options->dtmfcodec = H323_DTMF_RFC2833_PT; - ast_log(LOG_WARNING, "Unknown rfc2833 payload %s specified at line %d, using default %d\n", opt, v->lineno, options->dtmfcodec); + if (!opt) { + options->dtmfcodec[0] = H323_DTMF_RFC2833_PT; + } else if ((tmp >= 96) && (tmp < 128)) { + options->dtmfcodec[0] = tmp; + } else { + options->dtmfcodec[0] = H323_DTMF_RFC2833_PT; + ast_log(LOG_WARNING, "Unknown rfc2833 payload %s specified at line %d, using default %d\n", opt, v->lineno, options->dtmfcodec[0]); + } + } else if (!strcasecmp(val, "cisco")) { + options->dtmfmode |= H323_DTMF_CISCO; + if (!opt) { + options->dtmfcodec[1] = H323_DTMF_CISCO_PT; + } else if ((tmp >= 96) && (tmp < 128)) { + options->dtmfcodec[1] = tmp; + } else { + options->dtmfcodec[1] = H323_DTMF_CISCO_PT; + ast_log(LOG_WARNING, "Unknown Cisco DTMF payload %s specified at line %d, using default %d\n", opt, v->lineno, options->dtmfcodec[1]); } + } else if (!strcasecmp(v->value, "h245-signal")) { + options->dtmfmode |= H323_DTMF_SIGNAL; } else { - ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); - options->dtmfmode |= H323_DTMF_RFC2833; - options->dtmfcodec = H323_DTMF_RFC2833_PT; + ast_log(LOG_WARNING, "Unknown dtmf mode '%s' at line %d\n", v->value, v->lineno); } } else if (!strcasecmp(v->name, "dtmfcodec")) { ast_log(LOG_NOTICE, "Option %s at line %d is deprecated. Use dtmfmode=rfc2833[:<payload>] instead.\n", v->name, v->lineno); @@ -1282,7 +1296,7 @@ static int update_common_options(struct ast_variable *v, struct call_options *op if (tmp < 96) ast_log(LOG_WARNING, "Invalid %s value %s at line %d\n", v->name, v->value, v->lineno); else - options->dtmfcodec = tmp; + options->dtmfcodec[0] = tmp; } else if (!strcasecmp(v->name, "bridge")) { options->bridge = ast_true(v->value); } else if (!strcasecmp(v->name, "nat")) { @@ -2367,21 +2381,21 @@ static void hangup_connection(unsigned int call_reference, const char *token, in ast_mutex_unlock(&pvt->lock); } -static void set_dtmf_payload(unsigned call_reference, const char *token, int payload) +static void set_dtmf_payload(unsigned call_reference, const char *token, int payload, int is_cisco) { struct oh323_pvt *pvt; if (h323debug) - ast_log(LOG_DEBUG, "Setting DTMF payload to %d on %s\n", payload, token); + ast_log(LOG_DEBUG, "Setting %s DTMF payload to %d on %s\n", (is_cisco ? "Cisco" : "RFC2833"), payload, token); pvt = find_call_locked(call_reference, token); if (!pvt) { return; } if (pvt->rtp) { - ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event", 0); + ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", (is_cisco ? "cisco-telephone-event" : "telephone-event"), 0); } - pvt->dtmf_pt = payload; + pvt->dtmf_pt[is_cisco ? 1 : 0] = payload; ast_mutex_unlock(&pvt->lock); if (h323debug) ast_log(LOG_DEBUG, "DTMF payload on %s set to %d\n", token, payload); @@ -2750,7 +2764,8 @@ static int reload_config(int is_reload) memset(&global_options, 0, sizeof(global_options)); global_options.fastStart = 1; global_options.h245Tunneling = 1; - global_options.dtmfcodec = H323_DTMF_RFC2833_PT; + global_options.dtmfcodec[0] = H323_DTMF_RFC2833_PT; + global_options.dtmfcodec[1] = H323_DTMF_CISCO_PT; global_options.dtmfmode = 0; global_options.capability = GLOBAL_CAPABILITY; global_options.bridge = 1; /* Do native bridging by default */ diff --git a/channels/h323/ast_h323.cxx b/channels/h323/ast_h323.cxx index 61634aea9..be22ca64a 100644 --- a/channels/h323/ast_h323.cxx +++ b/channels/h323/ast_h323.cxx @@ -533,7 +533,7 @@ MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference, bridging = FALSE; progressSetup = progressAlert = 0; dtmfMode = 0; - dtmfCodec = (RTP_DataFrame::PayloadTypes)0; + dtmfCodec[0] = dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)0; redirect_reason = -1; #ifdef TUNNELLING tunnelOptions = remoteTunnelOptions = 0; @@ -664,7 +664,8 @@ void MyH323Connection::SetCallOptions(void *o, BOOL isIncoming) progressSetup = opts->progress_setup; progressAlert = opts->progress_alert; - dtmfCodec = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec; + dtmfCodec[0] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[0]; + dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[1]; dtmfMode = opts->dtmfmode; if (isIncoming) { @@ -1213,7 +1214,8 @@ void MyH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp) { - if ((dtmfMode & H323_DTMF_RFC2833)) { + /* Why we should check this? */ + if ((dtmfMode & (H323_DTMF_CISCO | H323_DTMF_RFC2833 | H323_DTMF_SIGNAL)) != 0) { if (h323debug) { cout << "\t-- Received user input tone (" << tone << ") from remote" << endl; } @@ -1243,10 +1245,10 @@ void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu) H245_Capability & cap = entry.m_capability; if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) { H245_AudioTelephonyEventCapability & atec = cap; - atec.m_dynamicRTPPayloadType = dtmfCodec; -// on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec); + atec.m_dynamicRTPPayloadType = dtmfCodec[0]; +// on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec[0]); if (h323debug) { - cout << "\t-- Transmitting RFC2833 on payload " << + cout << "\t-- Receiving RFC2833 on payload " << atec.m_dynamicRTPPayloadType << endl; } } @@ -1299,21 +1301,12 @@ BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCa }; #endif struct ast_codec_pref prefs; + RTP_DataFrame::PayloadTypes pt; if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) { return FALSE; } - const H323Capability * cap = remoteCaps.FindCapability(H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833]); - if (cap != NULL) { - RTP_DataFrame::PayloadTypes pt = ((H323_UserInputCapability*)cap)->GetPayloadType(); - on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt); - if ((dtmfMode & H323_DTMF_RFC2833) && (sendUserInputMode == SendUserInputAsTone)) - sendUserInputMode = SendUserInputAsInlineRFC2833; - if (h323debug) { - cout << "\t-- Inbound RFC2833 on payload " << pt << endl; - } - } memset(&prefs, 0, sizeof(prefs)); int peer_capabilities = 0; for (int i = 0; i < remoteCapabilities.GetSize(); ++i) { @@ -1346,6 +1339,32 @@ BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCa } } break; + case H323Capability::e_Data: + if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), CISCO_DTMF_RELAY)) { + pt = remoteCapabilities[i].GetPayloadType(); + if ((dtmfMode & H323_DTMF_CISCO) != 0) { + on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 1); +// if (sendUserInputMode == SendUserInputAsTone) +// sendUserInputMode = SendUserInputAsInlineRFC2833; + } + if (h323debug) { + cout << "\t-- Outbound Cisco RTP DTMF on payload " << pt << endl; + } + } + break; + case H323Capability::e_UserInput: + if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833])) { + pt = remoteCapabilities[i].GetPayloadType(); + if ((dtmfMode & H323_DTMF_RFC2833) != 0) { + on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 0); +// if (sendUserInputMode == SendUserInputAsTone) +// sendUserInputMode = SendUserInputAsInlineRFC2833; + } + if (h323debug) { + cout << "\t-- Outbound RFC2833 on payload " << pt << endl; + } + } + break; #if 0 case H323Capability::e_Video: for (int x = 0; vcodecs[x].asterisk_codec > 0; ++x) { @@ -1416,7 +1435,7 @@ BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel) return connectionState != ShuttingDownConnection; } -void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int pref_codec) +void MyH323Connection::SetCapabilities(int caps, int dtmf_mode, void *_prefs, int pref_codec) { PINDEX lastcap = -1; /* last common capability index */ int alreadysent = 0; @@ -1427,11 +1446,12 @@ void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int struct ast_format_list format; int frames_per_packet; int max_frames_per_packet; + H323Capability *cap; localCapabilities.RemoveAll(); if (h323debug) { - cout << "Setting capabilities to " << ast_getformatname_multiple(caps_str, sizeof(caps_str), cap) << endl; + cout << "Setting capabilities to " << ast_getformatname_multiple(caps_str, sizeof(caps_str), caps) << endl; ast_codec_pref_string(prefs, caps_str, sizeof(caps_str)); cout << "Capabilities in preference order is " << caps_str << endl; } @@ -1449,7 +1469,7 @@ void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int y <<= 1; codec = y; } - if (!(cap & codec) || (alreadysent & codec) || !(codec & AST_FORMAT_AUDIO_MASK)) + if (!(caps & codec) || (alreadysent & codec) || !(codec & AST_FORMAT_AUDIO_MASK)) continue; alreadysent |= codec; format = ast_codec_pref_getsize(prefs, codec); @@ -1518,23 +1538,64 @@ void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int } } - lastcap++; - lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245)); + cap = new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245); + if (cap && cap->IsUsable(*this)) { + lastcap++; + lastcap = localCapabilities.SetCapability(0, lastcap, cap); + } else if (cap) + delete cap; /* Capability is not usable */ - lastcap++; dtmfMode = dtmf_mode; - if ((dtmfMode & H323_DTMF_INBAND)) { - localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::BasicString)); - sendUserInputMode = SendUserInputAsString; - } else { - lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833)); - /* Cisco sends DTMF only through h245-alphanumeric or h245-signal, no support for RFC2833 */ - lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245)); - sendUserInputMode = SendUserInputAsTone; /* RFC2833 transmission handled at Asterisk level */ + if (h323debug) { + cout << "DTMF mode is " << (int)dtmfMode << endl; + } + if (dtmfMode) { + lastcap++; + if (dtmfMode == H323_DTMF_INBAND) { + cap = new H323_UserInputCapability(H323_UserInputCapability::BasicString); + if (cap && cap->IsUsable(*this)) { + lastcap = localCapabilities.SetCapability(0, lastcap, cap); + } else if (cap) + delete cap; /* Capability is not usable */ + sendUserInputMode = SendUserInputAsString; + } else { + if ((dtmfMode & H323_DTMF_RFC2833) != 0) { + cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833); + if (cap && cap->IsUsable(*this)) + lastcap = localCapabilities.SetCapability(0, lastcap, cap); + else { + dtmfMode |= H323_DTMF_SIGNAL; + if (cap) + delete cap; /* Capability is not usable */ + } + } + if ((dtmfMode & H323_DTMF_CISCO) != 0) { + /* Try Cisco's RTP DTMF relay too, but prefer RFC2833 or h245-signal */ + cap = new AST_CiscoDtmfCapability(); + if (cap && cap->IsUsable(*this)) { + lastcap = localCapabilities.SetCapability(0, lastcap, cap); + /* We cannot send Cisco RTP DTMFs, use h245-signal instead */ + dtmfMode |= H323_DTMF_SIGNAL; + } else { + dtmfMode |= H323_DTMF_SIGNAL; + if (cap) + delete cap; /* Capability is not usable */ + } + } + if ((dtmfMode & H323_DTMF_SIGNAL) != 0) { + /* Cisco usually sends DTMF correctly only through h245-alphanumeric or h245-signal */ + cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245); + if (cap && cap->IsUsable(*this)) + lastcap = localCapabilities.SetCapability(0, lastcap, cap); + else if (cap) + delete cap; /* Capability is not usable */ + } + sendUserInputMode = SendUserInputAsTone; /* RFC2833 transmission handled at Asterisk level */ + } } if (h323debug) { - cout << "Allowed Codecs:\n\t" << setprecision(2) << localCapabilities << endl; + cout << "Allowed Codecs for " << GetCallToken() << " (" << GetSignallingChannel()->GetLocalAddress() << "):\n\t" << setprecision(2) << localCapabilities << endl; } } diff --git a/channels/h323/ast_h323.h b/channels/h323/ast_h323.h index 4c85c2442..7199b0f34 100644 --- a/channels/h323/ast_h323.h +++ b/channels/h323/ast_h323.h @@ -112,7 +112,7 @@ public: unsigned progressAlert; int cause; - RTP_DataFrame::PayloadTypes dtmfCodec; + RTP_DataFrame::PayloadTypes dtmfCodec[2]; int dtmfMode; }; diff --git a/channels/h323/caps_h323.cxx b/channels/h323/caps_h323.cxx index 1a14e2337..ebb90f3f2 100644 --- a/channels/h323/caps_h323.cxx +++ b/channels/h323/caps_h323.cxx @@ -18,6 +18,7 @@ H323_REGISTER_CAPABILITY(AST_G729Capability, OPAL_G729); H323_REGISTER_CAPABILITY(AST_G729ACapability, OPAL_G729A); H323_REGISTER_CAPABILITY(AST_GSM0610Capability, OPAL_GSM0610); H323_REGISTER_CAPABILITY(AST_CiscoG726Capability, CISCO_G726r32); +H323_REGISTER_CAPABILITY(AST_CiscoDtmfCapability, CISCO_DTMF_RELAY); OPAL_MEDIA_FORMAT_DECLARE(OpalG711ALaw64kFormat, OPAL_G711_ALAW_64K, @@ -99,6 +100,18 @@ OPAL_MEDIA_FORMAT_DECLARE(OpalCiscoG726Format, 8, // 1 millisecond OpalMediaFormat::AudioTimeUnits, 0); +#if 0 +OPAL_MEDIA_FORMAT_DECLARE(OpalCiscoDTMFRelayFormat, + CISCO_DTMF_RELAY, + OpalMediaFormat::DefaultAudioSessionID, + (RTP_DataFrame::PayloadTypes)121, // Choose this for Cisco IOS compatibility + TRUE, // Needs jitter + 100, // bits/sec + 4, // bytes/frame + 8*150, // 150 millisecond + OpalMediaFormat::AudioTimeUnits, + 0); +#endif /* * Capability: G.711 diff --git a/channels/h323/chan_h323.h b/channels/h323/chan_h323.h index 8905e4eea..13296ed1a 100644 --- a/channels/h323/chan_h323.h +++ b/channels/h323/chan_h323.h @@ -52,7 +52,7 @@ typedef struct call_options { int progress_setup; int progress_alert; int progress_audio; - int dtmfcodec; + int dtmfcodec[2]; int dtmfmode; int capability; int bridge; @@ -172,7 +172,7 @@ extern answer_call_cb on_answer_call; /* This is a callback prototype function, called when we know which RTP payload type RFC2833 will be transmitted */ -typedef void (*rfc2833_cb)(unsigned, const char *, int); +typedef void (*rfc2833_cb)(unsigned, const char *, int, int); extern rfc2833_cb on_set_rfc2833_payload; typedef void (*hangup_cb)(unsigned, const char *, int); @@ -188,7 +188,9 @@ extern setpeercapabilities_cb on_setpeercapabilities; extern int h323debug; #define H323_DTMF_RFC2833 (1 << 0) -#define H323_DTMF_INBAND (1 << 1) +#define H323_DTMF_CISCO (1 << 1) +#define H323_DTMF_SIGNAL (1 << 2) +#define H323_DTMF_INBAND (1 << 3) #define H323_DTMF_RFC2833_PT 101 #define H323_DTMF_CISCO_PT 121 diff --git a/configs/h323.conf.sample b/configs/h323.conf.sample index 4fe37d843..ef8ff3004 100644 --- a/configs/h323.conf.sample +++ b/configs/h323.conf.sample @@ -28,7 +28,7 @@ port = 1720 ; ; User-Input Mode (DTMF) ; -; valid entries are: rfc2833, inband +; valid entries are: rfc2833, inband, cisco, h245-signal ; default is rfc2833 ;dtmfmode=rfc2833 ; @@ -38,6 +38,8 @@ port = 1720 ; To specify required payload type, put it after colon in dtmfmode ; option like ;dtmfmode=rfc2833:101 +; or +;dtmfmode=cisco:121 ; ; Set the gatekeeper ; DISCOVER - Find the Gk address using multicast |