Author |
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: December 28 2007 at 2:36pm | IP Logged
|
|
|
To: All LanScape customers and developers
Subject: Receiving and processing out of band RFC2833 DTMF
We get a lot of questions regarding how to handle out of band RFC2833 DTMF RTP payloads. At this time the v5.x.x.x media engine does not process these out of band payloads. It is the responsibility of the application to access the raw received RTP payload packets and “filter out” any RFC2833 DTMF packets in the media stream. Eventually we will include more complete DTMF support to the media engine – but hey, why wait for that. The solution below works well will little effort on the VOIP applications part.
By using the technique shown in the source code below, your VOIP app can handle RFC2833 out of band DTMF without a problem. Use this technique and get started with the development of that killer IVR VOIP app you’ve been dying to code up.
Figure 1: RTP packet callback handler.
Code:
// callback to receive raw RTP media packets from the media engine.
// this callback can be registered on a per phone line basis.
//
void __stdcall DtmfRawRtpCallback(RAW_RTP_DATA *pRawRtpData)
{
CVPhoneDlg *pDlg;
int NumDtmfPayloads;
int cnt;
BYTE DTMF_Event;
BOOL DTMF_E;
BOOL DTMF_R;
BYTE DTMF_Volume;
UINT DTMF_Duration;
UINT *pDtmfPayload;
UINT DtmfPayload;
// get the app specified instance data.
pDlg = (CVPhoneDlg *)pRawRtpData->pUserData;
if(pRawRtpData->Transmittin gPacket)
{
// this RTP data is being transmitted.
// do nothing.
//
// if you want to transmit RFC2833 DTMF packets,
// your source code can modify the ready-to-be-transmitted
// RTP data at this point.
//
}
else
{
// this RTP data is being received.
//
// look for RFC2833 DTMF payloads
//
// generally (99.9999% of the time) the payload type is 101 for
// out of band DTMF. This however depends on how the SIP call
// enpoints are actually configured.
if((pRawRtpData->pRtpHeader->PayloadType == 101) ||
(pRawRtpData->pRtpHeader-&g t;PayloadType == 127) // Avaya phones.
)
{
// this is "out of band" DTMF!
//
// the payload data is 4 bytes as per RFC 2833 (see section 3.5)
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | event |E|R| volume | duration |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Figure 1: Payload Format for Named Events
//
// access the DTMF payload as a 32 bit value.
pDtmfPayload = (UINT *)pRawRtpData->pSampleBuffer;
NumDtmfPayloads =
(pRawRtpData->RtpPacketLengthInBytes -
pRawRtpData->RtpHeaderLengthInBytes)/4;
for(cnt=0;cnt<NumDtmfPayloa ds;cnt++)
{
DtmfPayload = ntohl(pDtmfPayload[cnt]);
// parse the DTMF payload values.
//
// the DTMF key pressed or released.
DTMF_Event = DtmfPayload >> 24;
// the "end" bit.
DTMF_E = (DtmfPayload >> 23) & 0x01;
// reserved bit - not used.
DTMF_R = (DtmfPayload >> 22) & 0x01;
// the DTMF power level (volume).
DTMF_Volume = (DtmfPayload >> 16) & 0x3f;
// tone duration.
DTMF_Duration = DtmfPayload & 0xffff;
// now do something with the DTMF data we have.
//
// Notes:
//
// 1)
// The RTP header TimeStamp will be the same for
// all received DTMF RTP payloads for the DTMF digit being
// received. Use this fact to distinguish when new DTMF
// digits are being received. New DTMF digits will have a
// new RTP header TimeStamp.
//
// pRawRtpData->pRtpHeader->TimeStamp
//
// 2)
// When the DTMF digit terminates, the last few received DTMF
// RTP payloads will have the DTMF_E bit set indicating the
// end of DTMF. However, be careful using this. if your network
// connection gets unplugged while the other side sends the end
// packets, you could miss them. DTMF RTP payloads generally are
// received at the codec rate or possiblt every 50Ms as per the
// RFC. Your software should implement a timeout feature for all
// received RTP DTMF digits so that a network connection failure
// will not affect your ability to detect completion of DTMF
// signals.
//
}
// tell the media enigne to ignore this RTP DTMF packet.
// if you don't do this, the RTP receiver logic will try
// to interpret the DTMF payload as encoded audio.
pRawRtpData->ProcessRtpPacket = FALSE;
}
}
}
|
|
|
The code above is a callback handler that can be registered with the media engine on a per phone line basis. For complete details, see the EnableRawRtpPacketAccess() API procedure in the VOIP Media engine’s Software Developer’s Reference.
Once the callback proc is registered, it will get called for each phone line when RTP payloads are received. For most calls dealing with 20Ms sample block data, this callback proc will get called at a 50Hz rate per phone line. Make sure to perform the minimal amount of processing in this callback in order to minimize any receiver voice path latency. Note also, if this proc is registered for all phone lines, it will be called in a different thread context for each line. A good rule of thumb is to allow this callback to detect the DTMF RTP payloads and post the results somehow to another thread in your application.
You can go here and download a file that contains the actual code for the above callback procedure:
http://www.lanscapecorp.com/DevResources/Media Engine Software Examples/DTMF Callback.cpp
Have fun with your new DTMF capability!
Support
|
Back to Top |
|
|
juice Vetran
Joined: December 05 2006 Location: United States Posts: 139
|
Posted: February 11 2008 at 4:02pm | IP Logged
|
|
|
Hi support, we use a similar method to this for detecting DTMF with 101 Events.
One major thing we had to do was alter the 200 OK Sip Message going out. The reason was it was not returning the 101 Telephony Event as a supported CODEC in use. It also was not specifying format map. For an example, we had to add:
Code:
m=audio 8100 RTP/AVP 0 101
a=rtpmap:101 telephony-event/8000
a=fmtp:101 0-11
|
|
|
To the SDP so that SIP phones calling into the system would get a response indicating the 101 RTP support. Else, they would not know that the media engine supports the events so they don't send them. The INVITE Lanscape sends out, however, properly reports that it wants 101 Events. Just thought we would post this so you might change the behavior of the 200 OK (i.e. if User agent INVITE saying it supports that, you should return that) and/or to let others know how to make use of this.
However, there is one pretty big issue. Relaying this information to another side. I.e, crossing the lines between an in leg and an out bound leg. We have not been able to find a good way to do this. Ideally, we would want to transmit out the DTMF we received from one side to the RTP port of the other call leg.
Thoughts on how to go about relaying this information to the outbound leg? It is possible we over thought this, or API is changed, and there is an easy solution.
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: February 11 2008 at 4:17pm | IP Logged
|
|
|
Juice,
We are working on fully integrated DTMF in the product right now (native and .NET). We will support a unified DTMF model in v6 of the media engine. Complete in-band and out-of-band (RFC2833) DTMF. Customers purchasing a v5 media engine today will be given an inexpensive upgrade path for the v6 product.
You are correct regarding the “200 OK” responses previously generated by the media engine. That has been fixed.
About bridging DTMF across call legs:
For in-band, this will be automatic seeing as long as the audio channels are bridged, the DTMF will flow via the media. The app will receive DTMF related phone line events from the integrated Belcore compliant DTMF decoders but can really ignore the DTMF phone line events when bridging.
For out-of-band DTMF (RFC2833, DTMF, digits 0-15 plus Flash), the app will receive phone line events when the media engine detects DTMF. If the app wants to start DTMF on another line that is bridged (say via conference sessions or the old style line bridging via receive and transmit IVR lines), the app only need to call an API for the other bridged line to start DTMF transmitting out the other line.
Support
|
Back to Top |
|
|
ajdiaz Junior
Joined: December 10 2007 Location: United States Posts: 76
|
Posted: March 11 2008 at 12:07pm | IP Logged
|
|
|
Hi Support,
I have two issues trying to apply the technique suggested above.
(1) I am trying to convert the DtmfRawRtpCallback() method described above to C# to use with the LMEVoipManaged.dll, but the pRawRtpData object does not contain any instance of pRtpHeader.
The SDK Documentation for RAW_RTP_DATA says it does.
Code:
typedef struct
{
int PhoneLine;
BOOL TransmittingPacket;
RTP_HEADER *pRtpHeader;
unsigned long RtpHeaderLengthInBytes;
void *pSampleBuffer;
unsigned long SampleBufferLengthInBytes;
unsigned long RtpPacketLengthInBytes;
unsigned long MaxRtpPacketLength;
void *pUserData;
unsigned long NewSampleBufferLengthInBytes;
BOOL ProcessRtpPacket;
}RAW_RTP_DATA;
|
|
|
But in reality it does not. I do see that some properties were renamed. But I still only see 10 properties total and not 11 like described above.
(2) I cannot find EnableRawRtpPacketAccess() anywhere in the LMEVoipManaged.dll library either.
Please let me know what to do. Thanks.
-ajdiaz
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: March 11 2008 at 12:45pm | IP Logged
|
|
|
Hi Aj,
Because C# does not handle bit fields, the RTP header data passed to managed code is slightly different than that passed to native code applications. However, the managed code app still has the same byte for byte access to the full received RTP header and payload data.
The simplest way to get your app handling RFC2833 with the v5 media engine is to allow us to code up an example console app for you that you can download via your support FTP account.
That way you can steal whatever C# code is in the example. If you want us to do this, just repost. It will be easier than trying to explain all the bit/byte processing required.
The EnableRawRtpPacketAccess() API proc is a member of the RtpPacketAccess class. If you create an object of type RtpPacketAccess for use by each phone line and call the EnableRawRtpPacketAccess() API proc/member, you will have access to all raw received RTP packet bytes on a per phone line basis.
Support
|
Back to Top |
|
|
ajdiaz Junior
Joined: December 10 2007 Location: United States Posts: 76
|
Posted: March 11 2008 at 2:09pm | IP Logged
|
|
|
Support,
Yes, please code us an example console app in C# that can handle RFC2833 with the v5.12.8.1 of the media engine that will clearly identify the captured DTMF tone.
If possible have comments about considerations needed for larger scale applications if 512 lines are involved (if at all applicable).
Thanks.
-Alex
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: March 11 2008 at 5:38pm | IP Logged
|
|
|
Aj,
We will code up this sampe app right away in the morning.
Support
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: March 13 2008 at 8:18am | IP Logged
|
|
|
Aj,
We will post additional information in a moment in this thread:
Issues After Upgrading to DLL v5.12.8.1
http://www.lanscapecorp.com/forum/forum_posts.asp?TID=444&TP N=1
regarding the sample application we promised you. Hang on…
Support
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: December 02 2008 at 5:10am | IP Logged
|
|
|
VOIP Media Engine Release 6 is now shipping
Quick DTMF follow-up:
Release 6 of the media engine now handles all in-band and RFC2833 out-of-band DTMF generation and detection for your VOIP apps.
If anyone reads this thread, the topic and DTMF detection method discussed here were used prior to the VOIP Media Engine Release 6 being shipped.
With media engine Release 6, DTMF generation and detection are simple and automatic from the standpoint of your VOIP apps. Note however that the code and the technique discussed above can still be used if so desired.
Thanks,
Randal
Support
|
Back to Top |
|
|