summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h9
-rw-r--r--orkaudio/audiocaptureplugins/voip/Rtp.cpp4
-rw-r--r--orkaudio/audiocaptureplugins/voip/Rtp.h13
-rw-r--r--orkaudio/audiocaptureplugins/voip/RtpSession.cpp96
-rw-r--r--orkaudio/audiocaptureplugins/voip/RtpSession.h11
-rw-r--r--orkaudio/audiocaptureplugins/voip/VoIp.cpp31
6 files changed, 163 insertions, 1 deletions
diff --git a/orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h b/orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h
index ad6906d..7bf61d9 100644
--- a/orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h
+++ b/orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h
@@ -92,6 +92,15 @@ typedef struct
//unsigned int csrc[1]; // optional CSRC list
} RtpHeaderStruct;
+// Structure of RTP payload format for RTP events (ref RFC 2833, section
+// 3.5)
+typedef struct
+{
+ unsigned char event;
+ unsigned char er_volume;
+ unsigned short duration;
+} RtpEventPayloadFormat;
+
//===================================================================
// Cisco Callmanager -> endpoint messages
typedef struct
diff --git a/orkaudio/audiocaptureplugins/voip/Rtp.cpp b/orkaudio/audiocaptureplugins/voip/Rtp.cpp
index 5e53f3e..a35e519 100644
--- a/orkaudio/audiocaptureplugins/voip/Rtp.cpp
+++ b/orkaudio/audiocaptureplugins/voip/Rtp.cpp
@@ -41,3 +41,7 @@ void RtpPacketInfo::ToString(CStdString& string)
string.Format("%s,%d %s,%d seq:%u ts:%u len:%d type:%d", sourceIp, m_sourcePort, destIp, m_destPort, m_seqNum, m_timestamp, m_payloadSize, m_payloadType);
}
+void RtpEventInfo::ToString(CStdString& string)
+{
+ string.Format("event:%d e:%d r:%d volume:%d duration:%d timestamp:%u", m_event, m_e, m_r, m_volume, m_duration, m_startTimestamp);
+}
diff --git a/orkaudio/audiocaptureplugins/voip/Rtp.h b/orkaudio/audiocaptureplugins/voip/Rtp.h
index 0e50979..b1568b1 100644
--- a/orkaudio/audiocaptureplugins/voip/Rtp.h
+++ b/orkaudio/audiocaptureplugins/voip/Rtp.h
@@ -44,6 +44,19 @@ public:
};
typedef boost::shared_ptr<RtpPacketInfo> RtpPacketInfoRef;
+class RtpEventInfo
+{
+public:
+ void ToString(CStdString& string);
+
+ unsigned short m_event;
+ unsigned short m_e;
+ unsigned short m_r;
+ unsigned short m_volume;
+ unsigned short m_duration;
+ unsigned int m_startTimestamp;
+};
+typedef boost::shared_ptr<RtpEventInfo> RtpEventInfoRef;
#endif
diff --git a/orkaudio/audiocaptureplugins/voip/RtpSession.cpp b/orkaudio/audiocaptureplugins/voip/RtpSession.cpp
index 9a3b46a..b133317 100644
--- a/orkaudio/audiocaptureplugins/voip/RtpSession.cpp
+++ b/orkaudio/audiocaptureplugins/voip/RtpSession.cpp
@@ -57,6 +57,11 @@ RtpSession::RtpSession(CStdString& trackingId)
m_skinnyPassThruPartyId = 0;
memset(m_localMac, 0, sizeof(m_localMac));
memset(m_remoteMac, 0, sizeof(m_remoteMac));
+ m_currentRtpEvent = 65535;
+ m_lastEventEndSeqNo = 0;
+ m_currentDtmfDuration = 0;
+ m_currentRtpEventTs = 0;
+ m_currentDtmfVolume = 0;
}
void RtpSession::Stop()
@@ -478,6 +483,85 @@ void RtpSession::ReportMetadata()
g_captureEventCallBack(event, m_capturePort);
}
+void RtpSession::RecordRtpEvent()
+{
+ CaptureEventRef event(new CaptureEvent());
+ CStdString dtmfEventString, dtmfEventKey;
+
+ dtmfEventString.Format("event:%d timestamp:%d duration:%d volume:%d seqno:%d", m_currentRtpEvent, m_currentRtpEventTs,
+ m_currentDtmfDuration, m_currentDtmfVolume, m_currentSeqNo);
+ dtmfEventKey.Format("%d_RtpDtmfEvent", m_currentRtpEventTs);
+ event->m_type = CaptureEvent::EtKeyValue;
+ event->m_key = dtmfEventKey;
+ event->m_value = dtmfEventString;
+ g_captureEventCallBack(event, m_capturePort);
+
+ //LOG4CXX_INFO(m_log, "[" + m_trackingId + "] Recording RTP event [ " + dtmfEventString + " ]");
+}
+
+void RtpSession::HandleRtpEvent(RtpPacketInfoRef& rtpPacket)
+{
+ CStdString logMsg;
+
+ if(rtpPacket->m_payloadSize < sizeof(RtpEventPayloadFormat))
+ {
+ LOG4CXX_WARN(m_log, "[" + m_trackingId + "] Payload size for event packet too small");
+ return;
+ }
+
+ RtpEventPayloadFormat *payloadFormat = (RtpEventPayloadFormat *)rtpPacket->m_payload;
+ RtpEventInfoRef rtpEventInfo(new RtpEventInfo());
+
+ rtpEventInfo->m_event = (unsigned short)payloadFormat->event;
+ rtpEventInfo->m_e = (payloadFormat->er_volume & 0x80) ? 1 : 0;
+ rtpEventInfo->m_r = (payloadFormat->er_volume & 0x40) ? 1 : 0;
+ rtpEventInfo->m_volume = (unsigned short)(payloadFormat->er_volume & 0x3F);
+ rtpEventInfo->m_duration = ntohs(payloadFormat->duration);
+ rtpEventInfo->m_startTimestamp = rtpPacket->m_timestamp;
+
+ if((m_currentRtpEvent != 65535) && (m_currentRtpEvent != rtpEventInfo->m_event))
+ {
+ RecordRtpEvent();
+ }
+ else if(rtpEventInfo->m_e)
+ {
+ if((m_currentRtpEvent != 65535))
+ {
+ m_currentDtmfDuration = rtpEventInfo->m_duration;
+ m_currentDtmfVolume = rtpEventInfo->m_volume;
+ m_currentRtpEventTs = rtpEventInfo->m_startTimestamp;
+ m_currentSeqNo = rtpPacket->m_seqNum;
+
+ if(m_lastEventEndSeqNo != rtpPacket->m_seqNum)
+ {
+ RecordRtpEvent();
+ m_lastEventEndSeqNo = rtpPacket->m_seqNum;
+ }
+
+ m_currentRtpEvent = 65535;
+ }
+
+ rtpEventInfo->m_event = 65535;
+ rtpEventInfo->m_duration = 0;
+ }
+ else if((m_currentRtpEvent != 65535) && m_currentDtmfDuration && (rtpEventInfo->m_duration < m_currentDtmfDuration))
+ {
+ RecordRtpEvent();
+ }
+
+ if(!rtpEventInfo->m_e)
+ {
+ m_currentRtpEvent = rtpEventInfo->m_event;
+ }
+
+ m_currentDtmfDuration = rtpEventInfo->m_duration;
+ m_currentDtmfVolume = rtpEventInfo->m_volume;
+ m_currentRtpEventTs = rtpEventInfo->m_startTimestamp;
+ m_currentSeqNo = rtpPacket->m_seqNum;
+
+ return;
+}
+
// Returns false if the packet does not belong to the session (RTP timestamp discontinuity)
bool RtpSession::AddRtpPacket(RtpPacketInfoRef& rtpPacket)
{
@@ -510,6 +594,17 @@ bool RtpSession::AddRtpPacket(RtpPacketInfoRef& rtpPacket)
}
}
+ if(m_protocol == ProtSip)
+ {
+ /* Check if this is a telephone-event */
+ if(rtpPacket->m_payloadType == StringToInt(m_telephoneEventPayloadType))
+ {
+ // This is a telephone-event
+ HandleRtpEvent(rtpPacket);
+ return true;
+ }
+ }
+
// If we are on hold, unmark this
if(m_onHold)
{
@@ -705,6 +800,7 @@ void RtpSession::ReportSipInvite(SipInviteInfoRef& invite)
LOG4CXX_INFO(m_log, logMsg);
}
m_invites.push_front(invite);
+ m_telephoneEventPayloadType = invite->m_telephoneEventPayloadType;
// Gather extracted fields
std::copy(invite->m_extractedFields.begin(), invite->m_extractedFields.end(), std::inserter(m_tags, m_tags.begin()));
diff --git a/orkaudio/audiocaptureplugins/voip/RtpSession.h b/orkaudio/audiocaptureplugins/voip/RtpSession.h
index 02cc7ce..9c59593 100644
--- a/orkaudio/audiocaptureplugins/voip/RtpSession.h
+++ b/orkaudio/audiocaptureplugins/voip/RtpSession.h
@@ -42,6 +42,7 @@ public:
bool m_validated; // true when an RTP stream has been seen for the INVITE
bool m_attrSendonly; // true if the SDP has a:sendonly
std::map<CStdString, CStdString> m_extractedFields;
+ CStdString m_telephoneEventPayloadType;
time_t m_recvTime;
};
@@ -145,6 +146,8 @@ private:
void ProcessMetadataSkinny(RtpPacketInfoRef& rtpPacket);
void ReportMetadata();
void GenerateOrkUid();
+ void HandleRtpEvent(RtpPacketInfoRef& rtpPacket);
+ void RecordRtpEvent();
RtpPacketInfoRef m_lastRtpPacket;
RtpPacketInfoRef m_lastRtpPacketSide1;
@@ -174,6 +177,14 @@ private:
TcpAddressList m_rtpAddressList;
std::list<SipInviteInfoRef> m_invites;
std::map<CStdString, CStdString> m_tags;
+ CStdString m_telephoneEventPayloadType;
+
+ unsigned short m_currentRtpEvent;
+ unsigned int m_currentRtpEventTs;
+ unsigned int m_currentDtmfDuration;
+ unsigned int m_currentDtmfVolume;
+ unsigned int m_currentSeqNo;
+ unsigned int m_lastEventEndSeqNo;
};
typedef boost::shared_ptr<RtpSession> RtpSessionRef;
diff --git a/orkaudio/audiocaptureplugins/voip/VoIp.cpp b/orkaudio/audiocaptureplugins/voip/VoIp.cpp
index d85d05c..2d3faba 100644
--- a/orkaudio/audiocaptureplugins/voip/VoIp.cpp
+++ b/orkaudio/audiocaptureplugins/voip/VoIp.cpp
@@ -1031,7 +1031,7 @@ bool TryRtp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpH
u_short dest = ntohs(udpHeader->dest);
if(!(ntohs(udpHeader->source)%2) && !(ntohs(udpHeader->dest)%2) || DLLCONFIG.m_rtpDetectOnOddPorts) // udp ports usually even
{
- if((rtpHeader->pt <= 34 && rtpHeader->pt != 13) || rtpHeader->pt == 97 || rtpHeader->pt == 98) // pt=34 is H263 and is the last possible valid codec
+ if((rtpHeader->pt <= 34 && rtpHeader->pt != 13) || rtpHeader->pt == 97 || rtpHeader->pt == 98 || rtpHeader->pt > 98) // pt=34 is H263 and is the last possible valid codec, pt > 98 is for the case of SIP telephone-event
{ // pt=13 is CN (Comfort Noise)
result = true;
u_char* payload = (u_char *)rtpHeader + sizeof(RtpHeaderStruct);
@@ -1470,6 +1470,7 @@ bool TrySipInvite(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader
char* audioField = NULL;
char* connectionAddressField = NULL;
char* attribSendonly = memFindAfter("a=sendonly", (char*)udpPayload, sipEnd);
+ char* rtpmapAttribute = memFindAfter("\na=rtpmap:", (char*)udpPayload, sipEnd);
if(fromField)
{
@@ -1583,6 +1584,34 @@ bool TrySipInvite(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader
}
}
+ if(rtpmapAttribute)
+ {
+ CStdString rtpPayloadType, nextToken;
+ char *nextStep = NULL;
+
+ while(rtpmapAttribute && rtpmapAttribute < sipEnd)
+ {
+ GrabTokenSkipLeadingWhitespaces(rtpmapAttribute, sipEnd, rtpPayloadType);
+ nextToken.Format("%s ", rtpPayloadType);
+ nextStep = memFindAfter((char*)nextToken.c_str(), rtpmapAttribute, sipEnd);
+
+ /* We need our "nextStep" to contain at least the length
+ * of the string "telephone-event", 15 characters */
+ if(nextStep && ((sipEnd - nextStep) >= 15))
+ {
+ if(strncasecmp(nextStep, "telephone-event", 15) == 0)
+ {
+ /* Our DTMF packets are indicated using
+ * the payload type rtpPayloadType */
+ info->m_telephoneEventPayloadType = rtpPayloadType;
+ break;
+ }
+ }
+
+ rtpmapAttribute = memFindAfter("\na=rtpmap:", rtpmapAttribute, sipEnd);
+ }
+ }
+
if((unsigned int)info->m_fromRtpIp.s_addr == 0)
{
// In case connection address could not be extracted, use SIP invite sender IP address