> > A few month ago, I wrote a mprDecodeInbandDtmf.cpp that works quite
well.
> >
> > I can try to post it here if you are interested.
>
> I believe we all would be interested. So, please, post it to issue tracker
too.
>
> I suppose, it detect DTMF, mixed with audio stream, right? Does it use
> some third-party library for this?
No it doesn't use any third party library. I wrote everything from scratch.
However, it was for a test many months ago, and it's built against an old
rev of
sipxtapi-media-update. It's very hard to make a diff with current version.
---------------------------------------------
mprDecodeInbandDtmf.h
---------------------------------------------
#ifndef _MprDecodeInBandDtmf_h_
#define _MprDecodeInBandDtmf_h_
// APPLICATION INCLUDES
#include "mp/MpFlowGraphMsg.h"
#include "mp/MpAudioResource.h"
// DEFINES
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
/**
* @brief The "Audio from file" media processing resource
*/
class MprDecodeInBandDtmf : public MpAudioResource
{
/* //////////////////////////// PUBLIC ////////////////////////////////////
*/
public:
friend class MpConnection;
/* ============================ CREATORS ==================================
*/
///@name Creators
//@{
//:Constructor
MprDecodeInBandDtmf(const UtlString& rName, MpConnection* pConn, int
samplesPerFrame, int samplesPerSec);
//:Destructor
virtual
~MprDecodeInBandDtmf();
//@}
/* ============================ MANIPULATORS ==============================
*/
///@name Manipulators
//@{
//@}
/* ============================ ACCESSORS =================================
*/
///@name Accessors
//@{
//@}
/* ============================ INQUIRY ===================================
*/
///@name Inquiry
//@{
//@}
/* //////////////////////////// PROTECTED /////////////////////////////////
*/
protected:
/* //////////////////////////// PRIVATE ///////////////////////////////////
*/
private:
OsNotification* mpNotify;
MpConnection* mpConnection; ///< Link to the parent Connection.
int m_dtmfLastDigit;
int m_sameDtmfDigitCount;
int m_dtmfRound;
virtual UtlBoolean doProcessFrame(MpBufPtr inBufs[],
MpBufPtr outBufs[],
int inBufsSize,
int outBufsSize,
UtlBoolean isEnabled,
int samplesPerFrame=80,
int samplesPerSecond=8000);
/// Goertzel
double Goertzel( MpAudioSample *input, int numsamples, double frequency,
double samplerate);
/// Handle messages for this resource.
virtual UtlBoolean handleMessage(MpFlowGraphMsg& rMsg);
/// Copy constructor (not implemented for this class)
MprDecodeInBandDtmf(const MprDecodeInBandDtmf& rMprDecodeInBandDtmf);
/// Assignment operator (not implemented for this class)
MprDecodeInBandDtmf& operator=(const MprDecodeInBandDtmf& rhs);
};
/* ============================ INLINE METHODS ============================
*/
#endif // _MprDecodeInBandDtmf_h_
---------------------------------------------
mprDecodeInbandDtmf.cpp
---------------------------------------------
// SYSTEM INCLUDES
#include <assert.h>
#include <stdio.h>
#include <math.h>
#ifdef __pingtel_on_posix__
#include <stdlib.h>
#endif
// APPLICATION INCLUDES
#include "os/OsDefs.h"
#include "os/OsEvent.h"
#include "mp/MpCallFlowGraph.h"
#include "mp/MpBuf.h"
#include "mp/MprDecodeInBandDtmf.h"
#include "os/OsSysLog.h"
#include "../../sipXmediaAdapterLib\interface\mi\CpMediaInterface.h"
#define PI 3.1415926
#define PIt2 (2.0 * PI)
#define TwoPI PIt2
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
static const int NO_WAIT = 0;
// STATIC VARIABLE INITIALIZATIONS
/* //////////////////////////// PUBLIC ////////////////////////////////////
*/
/* ============================ CREATORS ==================================
*/
// Constructor
MprDecodeInBandDtmf::MprDecodeInBandDtmf(const UtlString& rName,
MpConnection* pConn,
int samplesPerFrame,
int samplesPerSec)
: MpAudioResource(rName, 0, 1, 1, 1, samplesPerFrame, samplesPerSec),
mpNotify(NULL), mpConnection(pConn),m_dtmfLastDigit(1000),
m_dtmfRound(0), m_sameDtmfDigitCount(0)
{
}
// Destructor
MprDecodeInBandDtmf::~MprDecodeInBandDtmf()
{
}
/* ============================ MANIPULATORS ==============================
*/
/* ============================ ACCESSORS =================================
*/
/* ============================ INQUIRY ===================================
*/
/* //////////////////////////// PROTECTED /////////////////////////////////
*/
/* //////////////////////////// PRIVATE ///////////////////////////////////
*/
UtlBoolean MprDecodeInBandDtmf::doProcessFrame(MpBufPtr inBufs[],
MpBufPtr outBufs[],
int inBufsSize,
int outBufsSize,
UtlBoolean isEnabled,
int samplesPerFrame,
int samplesPerSecond)
{
MpAudioBufPtr in;
MpAudioSample* input;
int numSamples = 0;
// try to pass along first input
if (inBufsSize > 0)
in.swap(inBufs[0]);
if (numOutputs() > 0)
outBufs[0] = in;
if (!isEnabled) {
return TRUE;
}
if( ! in.isValid()) {
return TRUE;
}
// GET SAMPLES
input = in->getSamples();
numSamples = in->getSamplesNumber();
int dtmfDigit = 1000;
double d697 = Goertzel(input, numSamples, 697, 8000);
double d770 = Goertzel(input, numSamples, 770, 8000);
double d852 = Goertzel(input, numSamples, 852, 8000);
double d941 = Goertzel(input, numSamples, 941, 8000);
double d1209 = Goertzel(input, numSamples, 1209, 8000);
double d1336 = Goertzel(input, numSamples, 1336, 8000);
double d1477 = Goertzel(input, numSamples, 1477, 8000);
double d1633 = Goertzel(input, numSamples, 1633, 8000);
int seuilInt = 150000;
if (d697 > seuilInt && d1209 > seuilInt)
dtmfDigit = 1;
else if (d697 > seuilInt && d1336 > seuilInt)
dtmfDigit = 2;
else if (d697 > seuilInt && d1477 > seuilInt)
dtmfDigit = 3;
else if (d697 > seuilInt && d1633 > seuilInt)
dtmfDigit = 12; //'A';
else if (d770 > seuilInt && d1209 > seuilInt)
dtmfDigit = 4;
else if (d770 > seuilInt && d1336 > seuilInt)
dtmfDigit = 5;
else if (d770 > seuilInt && d1477 > seuilInt)
dtmfDigit = 6;
else if (d770 > seuilInt && d1633 > seuilInt)
dtmfDigit = 13; // 'B';
else if (d852 > seuilInt && d1209 > seuilInt)
dtmfDigit = 7;
else if (d852 > seuilInt && d1336 > seuilInt)
dtmfDigit = 8;
else if (d852 > seuilInt && d1477 > seuilInt)
dtmfDigit = 9;
else if (d852 > seuilInt && d1633 > seuilInt)
dtmfDigit = 14; // 'C';
else if (d941 > seuilInt && d1209 > seuilInt)
dtmfDigit = 10; // '*';
else if (d941 > seuilInt && d1336 > seuilInt)
dtmfDigit = 0;
else if (d941 > seuilInt && d1477 > seuilInt)
dtmfDigit = 11; // '#';
else if (d941 > seuilInt && d1633 > seuilInt)
dtmfDigit = 15; //'D';
if( m_dtmfLastDigit == dtmfDigit )
{
m_sameDtmfDigitCount++;
if( m_sameDtmfDigitCount==4 && dtmfDigit != 1000 )
{
((MpCallFlowGraph*)mpFlowGraph)->mpMediaEventListener->onInBandDtmf(IDevice_
Audio, dtmfDigit );
}
}
else
{
if( dtmfDigit == 1000 )
{
if( m_sameDtmfDigitCount >= 4 )
{
m_sameDtmfDigitCount++;
}
else
{
m_sameDtmfDigitCount=0;
}
if( m_sameDtmfDigitCount >= 30 )
{
m_dtmfLastDigit = dtmfDigit;
m_sameDtmfDigitCount=0;
}
}
else
{
m_dtmfLastDigit = dtmfDigit;
m_sameDtmfDigitCount=0;
}
}
return TRUE;
}
double MprDecodeInBandDtmf::Goertzel( MpAudioSample *input, int numsamples,
double frequency, double samplerate)
{
double Qkn = 0;
double Qkn1 = 0;
double Qkn2, Wkn, Mk;
Wkn = TwoPI * frequency / samplerate;
Mk = 2 * cos(Wkn);
for(int i=0; i<numsamples ; i++ )
{
Qkn2 = Qkn1; Qkn1 = Qkn;
Qkn = input[i] + Mk * Qkn1 - Qkn2;
}
return sqrt(Qkn * Qkn + Qkn1 * Qkn1 - Mk * Qkn * Qkn1);
}
UtlBoolean MprDecodeInBandDtmf::handleMessage(MpFlowGraphMsg& rMsg)
{
switch (rMsg.getMsg()) {
default:
return MpAudioResource::handleMessage(rMsg);
break;
}
return TRUE;
}
/* ============================ FUNCTIONS =================================
*/
_______________________________________________
sipxtapi-dev mailing list
[email protected]
List Archive: http://list.sipfoundry.org/archive/sipxtapi-dev/