|
|
|
|
@ -24,7 +24,6 @@ public class DtmfTransformEngine
|
|
|
|
|
implements TransformEngine,
|
|
|
|
|
PacketTransformer
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Our class logger.
|
|
|
|
|
*/
|
|
|
|
|
@ -73,6 +72,22 @@ private enum ToneTransmissionState
|
|
|
|
|
END_SEQUENCE_INITIATED
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Array of all supported tones.
|
|
|
|
|
*/
|
|
|
|
|
private static final DTMFTone[] supportedTones =
|
|
|
|
|
new DTMFTone[]
|
|
|
|
|
{DTMFTone.DTMF_0, DTMFTone.DTMF_1, DTMFTone.DTMF_2, DTMFTone.DTMF_3,
|
|
|
|
|
DTMFTone.DTMF_4, DTMFTone.DTMF_5, DTMFTone.DTMF_6, DTMFTone.DTMF_7,
|
|
|
|
|
DTMFTone.DTMF_8, DTMFTone.DTMF_9, DTMFTone.DTMF_A, DTMFTone.DTMF_B,
|
|
|
|
|
DTMFTone.DTMF_C, DTMFTone.DTMF_D,
|
|
|
|
|
DTMFTone.DTMF_SHARP, DTMFTone.DTMF_STAR};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The dispatcher that is delivering tones to the media steam.
|
|
|
|
|
*/
|
|
|
|
|
private DTMFDispatcher dtmfDispatcher = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The status that this engine is currently in.
|
|
|
|
|
*/
|
|
|
|
|
@ -161,6 +176,15 @@ public RawPacket reverseTransform(RawPacket pkt)
|
|
|
|
|
|
|
|
|
|
if(currentDtmfPayload == pkt.getPayloadType())
|
|
|
|
|
{
|
|
|
|
|
DtmfRawPacket p = new DtmfRawPacket(pkt);
|
|
|
|
|
|
|
|
|
|
if (dtmfDispatcher == null)
|
|
|
|
|
{
|
|
|
|
|
dtmfDispatcher = new DTMFDispatcher();
|
|
|
|
|
new Thread(dtmfDispatcher).start();
|
|
|
|
|
}
|
|
|
|
|
dtmfDispatcher.addTonePacket(p);
|
|
|
|
|
|
|
|
|
|
// ignore received dtmf packets
|
|
|
|
|
// if jmf receive change in rtp payload stops reception
|
|
|
|
|
return null;
|
|
|
|
|
@ -293,4 +317,134 @@ public void stopSendingDTMF()
|
|
|
|
|
toneTransmissionState = ToneTransmissionState.END_REQUESTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stops threads that this transform engine is using for even delivery.
|
|
|
|
|
*/
|
|
|
|
|
public void stop()
|
|
|
|
|
{
|
|
|
|
|
if(dtmfDispatcher != null)
|
|
|
|
|
dtmfDispatcher.stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A simple thread that waits for new tones to be reported from incoming
|
|
|
|
|
* RTP packets and then delivers them to the <tt>AudioMediaStream</tt>
|
|
|
|
|
* associated with this engine. The reason we need to do this in a separate
|
|
|
|
|
* thread is of course the time sensitive nature of incoming RTP packets.
|
|
|
|
|
*/
|
|
|
|
|
private class DTMFDispatcher
|
|
|
|
|
implements Runnable
|
|
|
|
|
{
|
|
|
|
|
/** Indicates whether this thread is supposed to be running */
|
|
|
|
|
private boolean isRunning = false;
|
|
|
|
|
|
|
|
|
|
/** The tone that we last received from the reverseTransform thread*/
|
|
|
|
|
private DTMFTone lastReceivedTone = null;
|
|
|
|
|
|
|
|
|
|
/** The tone that we last received from the reverseTransform thread*/
|
|
|
|
|
private DTMFTone lastReportedTone = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Have we received end of the currently started tone.
|
|
|
|
|
*/
|
|
|
|
|
private boolean toEnd = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Waits for new tone to be reported via the <tt>addTonePacket()</tt>
|
|
|
|
|
* method and then delivers them to the <tt>AudioMediaStream</tt> that
|
|
|
|
|
* we are associated with.
|
|
|
|
|
*/
|
|
|
|
|
public void run()
|
|
|
|
|
{
|
|
|
|
|
isRunning = true;
|
|
|
|
|
|
|
|
|
|
DTMFTone temp = null;
|
|
|
|
|
|
|
|
|
|
while(isRunning)
|
|
|
|
|
{
|
|
|
|
|
synchronized(this)
|
|
|
|
|
{
|
|
|
|
|
if(lastReceivedTone == null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
wait();
|
|
|
|
|
}
|
|
|
|
|
catch (InterruptedException ie) {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
temp = lastReceivedTone;
|
|
|
|
|
// make lastReportedLevels to null
|
|
|
|
|
// so we will wait for the next tone on next iteration
|
|
|
|
|
lastReceivedTone = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(temp != null
|
|
|
|
|
&& ((lastReportedTone == null && !toEnd)
|
|
|
|
|
|| (lastReportedTone != null && toEnd)))
|
|
|
|
|
{
|
|
|
|
|
//now notify our listener
|
|
|
|
|
if (mediaStream != null)
|
|
|
|
|
{
|
|
|
|
|
mediaStream.fireDTMFEvent(temp, toEnd);
|
|
|
|
|
if(toEnd)
|
|
|
|
|
lastReportedTone = null;
|
|
|
|
|
else
|
|
|
|
|
lastReportedTone = temp;
|
|
|
|
|
toEnd = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A packet that we should convert to tone and deliver
|
|
|
|
|
* to our media stream and its listeners in a separate thread.
|
|
|
|
|
*
|
|
|
|
|
* @param p the packet we will convert and deliver.
|
|
|
|
|
*/
|
|
|
|
|
public void addTonePacket(DtmfRawPacket p)
|
|
|
|
|
{
|
|
|
|
|
synchronized(this)
|
|
|
|
|
{
|
|
|
|
|
this.lastReceivedTone = getToneFromPacket(p);
|
|
|
|
|
this.toEnd = p.isEnd();
|
|
|
|
|
|
|
|
|
|
notifyAll();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Causes our run method to exit so that this thread would stop
|
|
|
|
|
* handling levels.
|
|
|
|
|
*/
|
|
|
|
|
public void stop()
|
|
|
|
|
{
|
|
|
|
|
synchronized(this)
|
|
|
|
|
{
|
|
|
|
|
this.lastReceivedTone = null;
|
|
|
|
|
isRunning = false;
|
|
|
|
|
|
|
|
|
|
notifyAll();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Maps DTMF packet codes to our DTMFTone objects.
|
|
|
|
|
* @param p the packet
|
|
|
|
|
* @return the corresponding tone.
|
|
|
|
|
*/
|
|
|
|
|
private DTMFTone getToneFromPacket(DtmfRawPacket p)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < supportedTones.length; i++)
|
|
|
|
|
{
|
|
|
|
|
DTMFTone t = supportedTones[i];
|
|
|
|
|
if(t.getCode() == p.getCode())
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|