/** * session.cpp * Yet Another RTP Stack * This file is part of the YATE Project http://YATE.null.ro * * Yet Another Telephony Engine - a fully featured software PBX and IVR * Copyright (C) 2004-2006 Null Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include using namespace TelEngine; bool RTPBaseIO::dataPayload(int type) { if ((type >= -1) && (type <= 127)) { m_dataType = type; return true; } return false; } bool RTPBaseIO::eventPayload(int type) { if ((type >= -1) && (type <= 127)) { m_eventType = type; return true; } return false; } bool RTPBaseIO::silencePayload(int type) { if ((type >= -1) && (type <= 127)) { m_silenceType = type; return true; } return false; } RTPReceiver::~RTPReceiver() { setDejitter(0); } void RTPReceiver::setDejitter(RTPDejitter* dejitter) { if (dejitter == m_dejitter) return; DDebug(DebugInfo,"RTP setting new dejitter %p [%p]",dejitter,this); RTPDejitter* tmp = m_dejitter; m_dejitter = 0; if (tmp) { tmp->group(0); tmp->destruct(); } // make the dejitter buffer belong to the same group as the session if (dejitter && m_session) dejitter->group(m_session->group()); m_dejitter = dejitter; } void RTPReceiver::rtpData(const void* data, int len) { // trivial check for basic fields validity if ((len < 12) || !data) return; const unsigned char* pc = (const unsigned char*)data; // check protocol version number if ((pc[0] & 0xc0) != 0x80) return; // check if padding is present and remove it if (pc[0] & 0x20) { len -= pc[len-1]; if (len < 12) return; } bool ext = (pc[0] & 0x10) != 0; int cc = pc[0] & 0x0f; bool marker = (pc[1] & 0x80) != 0; int typ = pc[1] & 0x7f; u_int16_t seq = ((u_int16_t)pc[2] << 8) | pc[3]; u_int32_t ts = ((u_int32_t)pc[4] << 24) | ((u_int32_t)pc[5] << 16) | ((u_int32_t)pc[6] << 8) | pc[7]; u_int32_t ss = ((u_int32_t)pc[8] << 24) | ((u_int32_t)pc[9] << 16) | ((u_int32_t)pc[10] << 8) | pc[11]; // grab some data at the first packet received or resync if (m_ssrcInit) { m_ssrcInit = false; m_ssrc = ss; m_ts = ts - m_tsLast; m_seq = seq-1; m_warn = true; } if (ss != m_ssrc) rtpNewSSRC(ss); // check if the SSRC is still unchanged if (ss != m_ssrc) { if (m_warn) { m_warn = false; Debug(DebugWarn,"RTP Received SSRC %08X but expecting %08X [%p]", ss,m_ssrc,this); } return; } // substraction with overflow int16_t ds = seq - m_seq; // received duplicate or delayed packet? if (ds <= 0) { DDebug(DebugMild,"RTP received SEQ %u while current is %u [%p]",seq,m_seq,this); return; } // keep track of the last sequence number and timestamp we have seen m_seq = seq; m_tsLast = ts - m_ts; // skip over header and any CSRC pc += 12+(4*cc); len -= 12+(4*cc); // check if extension is present and skip it if (ext) { if (len < 4) return; int xl = ((int)pc[2] << 8) | pc[3]; pc += xl+4; len -= xl+4; } if (len < 0) return; if (!len) pc = 0; rtpRecv(marker,typ,m_tsLast,pc,len); } void RTPReceiver::rtcpData(const void* data, int len) { } bool RTPReceiver::rtpRecv(bool marker, int payload, unsigned int timestamp, const void* data, int len) { if ((payload != dataPayload()) && (payload != eventPayload()) && (payload != silencePayload())) rtpNewPayload(payload,timestamp); if (payload == eventPayload()) return decodeEvent(marker,timestamp,data,len); if (payload == silencePayload()) return decodeSilence(marker,timestamp,data,len); finishEvent(timestamp); if (payload == dataPayload()) { #if 0 // dejitter is broken - don't use it if (m_dejitter) return m_dejitter->rtpRecvData(marker,timestamp,data,len); else #endif return rtpRecvData(marker,timestamp,data,len); } return false; } bool RTPReceiver::rtpRecvData(bool marker, unsigned int timestamp, const void* data, int len) { return m_session && m_session->rtpRecvData(marker,timestamp,data,len); } bool RTPReceiver::rtpRecvEvent(int event, char key, int duration, int volume, unsigned int timestamp) { return m_session && m_session->rtpRecvEvent(event,key,duration,volume,timestamp); } void RTPReceiver::rtpNewPayload(int payload, unsigned int timestamp) { if (m_session) m_session->rtpNewPayload(payload,timestamp); } void RTPReceiver::rtpNewSSRC(u_int32_t newSsrc) { if (m_session) m_session->rtpNewSSRC(newSsrc); } bool RTPReceiver::decodeEvent(bool marker, unsigned int timestamp, const void* data, int len) { // we support only basic RFC2833, no RFC2198 redundancy if (len != 4) return false; const unsigned char* pc = (const unsigned char*)data; int event = pc[0]; int vol = pc[1] & 0x3f; bool end = (pc[1] & 0x80) != 0; int duration = ((int)pc[2] << 8) | pc[3]; if (m_evTs && (m_evNum >= 0)) { if ((m_evNum != event) && (m_evTs <= timestamp)) pushEvent(m_evNum,timestamp - m_evTs,m_evVol,m_evTs); } m_evVol = vol; if (!end) { m_evTs = timestamp; m_evNum = event; return true; } if (m_evTs > timestamp) return false; // make sure we don't see the same event again m_evTs = timestamp+1; m_evNum = -1; pushEvent(event,duration,vol,timestamp); return true; } bool RTPReceiver::decodeSilence(bool marker, unsigned int timestamp, const void* data, int len) { return false; } void RTPReceiver::finishEvent(unsigned int timestamp) { if ((m_evNum < 0) || !m_evTs) return; int duration = timestamp - m_evTs; if (duration < 10000) return; timestamp = m_evTs; m_evTs = 0; pushEvent(m_evNum,duration,m_evVol,timestamp); } bool RTPReceiver::pushEvent(int event, int duration, int volume, unsigned int timestamp) { static const char dtmf[] = "0123456789*#ABCDF"; char key = (event <= 16) ? dtmf[event] : 0; return rtpRecvEvent(event,key,duration,volume,timestamp); } void RTPReceiver::timerTick(const Time& when) { } RTPSender::RTPSender(RTPSession* session, bool randomTs) : RTPBaseIO(session), m_evTime(0), m_tsLast(0) { if (randomTs) m_ts = ::random() & ~1; } bool RTPSender::rtpSend(bool marker, int payload, unsigned int timestamp, const void* data, int len) { if (!(m_session && m_session->transport())) return false; if (!data) len = 0; payload &= 0x7f; if (marker) payload |= 0x80; m_tsLast = timestamp; timestamp += m_ts; if (m_ssrcInit) { m_ssrcInit = false; m_ssrc = ::random(); } m_seq++; DataBlock buf(0,len+12); unsigned char* pc = (unsigned char*)buf.data(); *pc++ = 0x80; *pc++ = payload; *pc++ = (unsigned char)(m_seq >> 8); *pc++ = (unsigned char)(m_seq & 0xff); *pc++ = (unsigned char)(timestamp >> 24); *pc++ = (unsigned char)(timestamp >> 16); *pc++ = (unsigned char)(timestamp >> 8); *pc++ = (unsigned char)(timestamp & 0xff); *pc++ = (unsigned char)(m_ssrc >> 24); *pc++ = (unsigned char)(m_ssrc >> 16); *pc++ = (unsigned char)(m_ssrc >> 8); *pc++ = (unsigned char)(m_ssrc & 0xff); if (data && len) ::memcpy(pc,data,len); static_cast(m_session->transport())->rtpData(buf.data(),buf.length()); return true; } bool RTPSender::rtpSendData(bool marker, unsigned int timestamp, const void* data, int len) { if (dataPayload() < 0) return false; if (sendEventData(timestamp)) return true; return rtpSend(marker,dataPayload(),timestamp,data,len); } bool RTPSender::rtpSendEvent(int event, int duration, int volume, unsigned int timestamp) { // send as RFC2833 if we have the payload type set if (eventPayload() < 0) return false; if ((duration <= 50) || (duration > 10000)) duration = 1600; if (!timestamp) timestamp = m_tsLast; if (m_evTs) { Debug(DebugNote,"RFC 2833 overlapped in RTP event %d, session %p, fixing.", event,m_session); // the timestamp must always advance to avoid misdetections if (timestamp == m_evTs) m_tsLast = timestamp = timestamp + 2; // make sure we send an event end packet m_evTime = 0; sendEventData(timestamp); } m_evTs = timestamp; m_evNum = event; m_evVol = volume; m_evTime = duration; return sendEventData(timestamp); } bool RTPSender::rtpSendKey(char key, int duration, int volume, unsigned int timestamp) { int event = 0; if ((key >= '0') && (key <= '9')) event = key - '0'; else if (key == '*') event = 10; else if (key == '#') event = 11; else if ((key >= 'A') && (key <= 'D')) event = key + 12 - 'A'; else if ((key >= 'a') && (key <= 'd')) event = key + 12 - 'a'; else if ((key == 'F') || (key == 'f')) event = 16; else return false; return rtpSendEvent(event,duration,volume,timestamp); } bool RTPSender::sendEventData(unsigned int timestamp) { if (m_evTs) { if (eventPayload() < 0) { m_evTs = 0; return false; } int duration = timestamp - m_evTs; char buf[4]; buf[0] = m_evNum; buf[1] = m_evVol & 0x7f; buf[2] = duration >> 8; buf[3] = duration & 0xff; unsigned int tstamp = m_evTs; if (duration >= m_evTime) { buf[1] |= 0x80; m_evTs = 0; // repeat the event end packet to increase chances it gets seen if (rtpSend(!duration,eventPayload(),tstamp,buf,sizeof(buf))) m_seq--; } bool ok = rtpSend(!duration,eventPayload(),tstamp,buf,sizeof(buf)); // have to update last timestamp since we sent the event start stamp m_tsLast = timestamp; return ok; } return false; } void RTPSender::timerTick(const Time& when) { } RTPSession::RTPSession() : m_transport(0), m_direction(FullStop), m_send(0), m_recv(0) { DDebug(DebugInfo,"RTPSession::RTPSession() [%p]",this); } RTPSession::~RTPSession() { DDebug(DebugInfo,"RTPSession::~RTPSession() [%p]",this); direction(FullStop); group(0); transport(0); } void RTPSession::timerTick(const Time& when) { if (m_send) static_cast(m_send)->timerTick(when); if (m_recv) static_cast(m_recv)->timerTick(when); } void RTPSession::rtpData(const void* data, int len) { if ((m_direction & RecvOnly) == 0) return; if (m_recv) m_recv->rtpData(data,len); } void RTPSession::rtcpData(const void* data, int len) { if ((m_direction & RecvOnly) == 0) return; if (m_recv) m_recv->rtcpData(data,len); } bool RTPSession::rtpRecvData(bool marker, unsigned int timestamp, const void* data, int len) { XDebug(DebugAll,"RTPSession::rtpRecv(%s,%u,%p,%d) [%p]", String::boolText(marker),timestamp,data,len,this); return false; } bool RTPSession::rtpRecvEvent(int event, char key, int duration, int volume, unsigned int timestamp) { XDebug(DebugAll,"RTPSession::rtpRecvEvent(%d,%02x,%d,%d,%u) [%p]", event,key,duration,volume,timestamp,this); return false; } void RTPSession::rtpNewPayload(int payload, unsigned int timestamp) { XDebug(DebugAll,"RTPSession::rtpNewPayload(%d,%u) [%p]", payload,timestamp,this); } void RTPSession::rtpNewSSRC(u_int32_t newSsrc) { XDebug(DebugAll,"RTPSession::rtpNewSSRC(%08X) [%p]", newSsrc,this); } RTPSender* RTPSession::createSender() { return new RTPSender(this); } RTPReceiver* RTPSession::createReceiver() { return new RTPReceiver(this); } RTPTransport* RTPSession::createTransport() { RTPTransport* trans = new RTPTransport(); trans->group(group()); return trans; } bool RTPSession::initGroup(int msec, Thread::Priority prio) { if (m_group) return true; // try to pick the grop from the transport if it has one if (m_transport) group(m_transport->group()); if (!m_group) group(new RTPGroup(msec,prio)); if (!m_group) return false; if (m_transport) m_transport->group(m_group); return true; } bool RTPSession::initTransport() { if (m_transport) return true; transport(createTransport()); return (m_transport != 0); } void RTPSession::transport(RTPTransport* trans) { DDebug(DebugInfo,"RTPSession::transport(%p) old=%p [%p]",trans,m_transport,this); if (trans == m_transport) return; RTPTransport* tmp = m_transport; m_transport = 0; if (tmp) { tmp->setProcessor(0); tmp->destruct(); } m_transport = trans; if (m_transport) m_transport->setProcessor(this); else m_direction = FullStop; } void RTPSession::sender(RTPSender* send) { DDebug(DebugInfo,"RTPSession::sender(%p) old=%p [%p]",send,m_send,this); if (send == m_send) return; RTPSender* tmp = m_send; m_send = send; if (tmp) delete tmp; } void RTPSession::receiver(RTPReceiver* recv) { DDebug(DebugInfo,"RTPSession::receiver(%p) old=%p [%p]",recv,m_recv,this); if (recv == m_recv) return; RTPReceiver* tmp = m_recv; m_recv = recv; if (tmp) delete tmp; } bool RTPSession::direction(Direction dir) { DDebug(DebugInfo,"RTPSession::direction(%d) old=%d [%p]",dir,m_direction,this); if ((dir != FullStop) && !m_transport) return false; if (dir & RecvOnly) { if (!m_recv) receiver(createReceiver()); } else receiver(0); if (dir & SendOnly) { if (!m_send) sender(createSender()); } else sender(0); m_direction = dir; return true; } bool RTPSession::dataPayload(int type) { if (m_recv || m_send) { DDebug(DebugInfo,"RTPSession::dataPayload(%d) [%p]",type,this); bool ok = (!m_recv) || m_recv->dataPayload(type); return ((!m_send) || m_send->dataPayload(type)) && ok; } return false; } bool RTPSession::eventPayload(int type) { if (m_recv || m_send) { DDebug(DebugInfo,"RTPSession::eventPayload(%d) [%p]",type,this); bool ok = (!m_recv) || m_recv->eventPayload(type); return ((!m_send) || m_send->eventPayload(type)) && ok; } return false; } bool RTPSession::silencePayload(int type) { if (m_recv || m_send) { DDebug(DebugInfo,"RTPSession::silencePayload(%d) [%p]",type,this); bool ok = (!m_recv) || m_recv->silencePayload(type); return ((!m_send) || m_send->silencePayload(type)) && ok; } return false; } /* vi: set ts=8 sw=4 sts=4 noet: */