// Set new media list. Return true if changed bool SDPSession::setMedia(ObjList* media) { if (media == m_rtpMedia) return false; DDebug(m_enabler,DebugAll,"SDPSession::setMedia(%p) [%p]",media,m_ptr); ObjList* tmp = m_rtpMedia; m_rtpMedia = media; bool chg = m_rtpMedia != 0; if (tmp) { chg = false; for (ObjList* o = tmp->skipNull(); o; o = o->skipNext()) { SDPMedia* m = static_cast<SDPMedia*>(o->get()); if (media && m->sameAs(static_cast<SDPMedia*>((*media)[*m]),m_parser->ignorePort())) continue; chg = true; mediaChanged(*m); } TelEngine::destruct(tmp); } printRtpMedia("Set media"); return chg; }
NamedList& NamedList::setParam(const String& name, const char* value) { XDebug(DebugInfo,"NamedList::setParam(\"%s\",\"%s\")",name.c_str(),value); ObjList *p = m_params.skipNull(); while (p) { NamedString *s = static_cast<NamedString*>(p->get()); if (s->name() == name) { *s = value; return *this; } ObjList* next = p->skipNext(); if (next) p = next; else break; } if (p) p->append(new NamedString(name,value)); else m_params.append(new NamedString(name,value)); return *this; }
bool ExpEvaluator::runAllFields(ObjList& stack, GenObject* context) const { DDebug(this,DebugAll,"runAllFields(%p,%p)",&stack,context); bool ok = true; for (ObjList* l = stack.skipNull(); l; l = l->skipNext()) { const ExpOperation* o = static_cast<const ExpOperation*>(l->get()); if (o->barrier()) break; if (o->opcode() != OpcField) continue; ObjList tmp; if (runField(tmp,*o,context)) { ExpOperation* val = popOne(tmp); if (val) l->set(val); else ok = false; } else ok = false; } return ok; }
// Repeatedly calls dispatchRtp() for each media in the list // Update it on success. Remove it on failure bool SDPSession::dispatchRtp(const char* addr, bool start, RefObject* context) { if (!m_rtpMedia) return false; DDebug(m_parser,DebugAll,"SDPSession::dispatchRtp(%s,%u,%p) [%p]", addr,start,context,this); bool ok = false; ObjList* o = m_rtpMedia->skipNull(); while (o) { SDPMedia* m = static_cast<SDPMedia*>(o->get()); if (dispatchRtp(m,addr,start,true,context)) { ok = true; o = o->skipNext(); } else { Debug(m_parser,DebugMild, "Removing failed SDP media '%s' format '%s' from offer [%p]", m->c_str(),m->format().safe(),this); o->remove(); o = o->skipNull(); } } return ok; }
// Creates a SDP body from transport address and list of media descriptors // Use own list if given media list is 0 MimeSdpBody* SDPSession::createSDP(const char* addr, ObjList* mediaList) { DDebug(m_parser,DebugAll,"SDPSession::createSDP('%s',%p) [%p]",addr,mediaList,this); if (!mediaList) mediaList = m_rtpMedia; // if we got no media descriptors we simply create no SDP if (!mediaList) return 0; if (m_sdpSession) ++m_sdpVersion; else m_sdpVersion = m_sdpSession = Time::secNow(); // no address means on hold or muted String origin; origin << "yate " << m_sdpSession << " " << m_sdpVersion; origin << " IN IP4 " << (addr ? addr : m_host.safe()); String conn; conn << "IN IP4 " << (addr ? addr : "0.0.0.0"); MimeSdpBody* sdp = new MimeSdpBody; sdp->addLine("v","0"); sdp->addLine("o",origin); sdp->addLine("s",m_parser->m_sessionName); sdp->addLine("c",conn); sdp->addLine("t","0 0"); Lock lock(m_parser); bool defcodecs = m_parser->m_codecs.getBoolValue("default",true); for (ObjList* ml = mediaList->skipNull(); ml; ml = ml->skipNext()) { SDPMedia* m = static_cast<SDPMedia*>(ml->get()); String mline(m->fmtList()); ObjList* l = mline.split(',',false); mline = *m; mline << " " << (m->localPort() ? m->localPort().c_str() : "0") << " " << m->transport(); ObjList* map = m->mappings().split(',',false); ObjList rtpmap; String frm; int ptime = 0; ObjList* f = l; for (; f; f = f->next()) { String* s = static_cast<String*>(f->get()); if (s) { int mode = 0; if (*s == "ilbc20") ptime = mode = 20; else if (*s == "ilbc30") ptime = mode = 30; else if (*s == "g729b") continue; int payload = s->toInteger(SDPParser::s_payloads,-1); int defcode = payload; String tmp = *s; tmp << "="; for (ObjList* pl = map; pl; pl = pl->next()) { String* mapping = static_cast<String*>(pl->get()); if (!mapping) continue; if (mapping->startsWith(tmp)) { payload = -1; tmp = *mapping; tmp >> "=" >> payload; XDebug(m_parser,DebugAll,"RTP mapped payload %d for '%s' [%p]", payload,s->c_str(),this); break; } } if (payload >= 0) { if (defcode < 0) defcode = payload; const char* map = lookup(defcode,SDPParser::s_rtpmap); if (map && m_parser->m_codecs.getBoolValue(*s,defcodecs && DataTranslator::canConvert(*s))) { frm << " " << payload; String* temp = new String("rtpmap:"); *temp << payload << " " << map; rtpmap.append(temp); if (mode) { temp = new String("fmtp:"); *temp << payload << " mode=" << mode; rtpmap.append(temp); } if (*s == "g729") { temp = new String("fmtp:"); *temp << payload << " annexb=" << ((0 != l->find("g729b")) ? "yes" : "no"); rtpmap.append(temp); } else if (*s == "amr") { temp = new String("fmtp:"); *temp << payload << " octet-align=0"; rtpmap.append(temp); } else if (*s == "amr-o") { temp = new String("fmtp:"); *temp << payload << " octet-align=1"; rtpmap.append(temp); } if(s->length()) { String key("fmtp-"); key << *s; for(unsigned int i = 0; i < m->length(); ++i) { const NamedString *ns = m->getParam(i); if(ns && ns->name() == key) { temp = new String("fmtp:"); *temp << payload << " " << *ns; rtpmap.append(temp); } } } } } } } TelEngine::destruct(l); TelEngine::destruct(map); if ((m_rfc2833 >= 0) && frm && m->isAudio()) { int rfc2833 = m->rfc2833().toInteger(m_rfc2833); if (rfc2833 < 96 || rfc2833 > 127) rfc2833 = 101; // claim to support telephone events frm << " " << rfc2833; String* s = new String; *s << "rtpmap:" << rfc2833 << " telephone-event/8000"; rtpmap.append(s); } if (frm.null()) { if (m->isAudio() || !m->fmtList()) { Debug(m_parser,DebugMild,"No formats for '%s', excluding from SDP [%p]", m->c_str(),this); continue; } Debug(m_parser,DebugInfo,"Assuming formats '%s' for media '%s' [%p]", m->fmtList(),m->c_str(),this); frm << " " << m->fmtList(); // brutal but effective for (char* p = const_cast<char*>(frm.c_str()); *p; p++) { if (*p == ',') *p = ' '; } } if (ptime) { String* temp = new String("ptime:"); *temp << ptime; rtpmap.append(temp); } sdp->addLine("m",mline + frm); bool enc = false; if (m->isModified()) { unsigned int n = m->length(); for (unsigned int i = 0; i < n; i++) { const NamedString* param = m->getParam(i); if (param) { String tmp = param->name(); if (tmp.startsWith("fmtp-")) continue; if (*param) tmp << ":" << *param; sdp->addLine("a",tmp); enc = enc || (param->name() == "encryption"); } } } for (f = rtpmap.skipNull(); f; f = f->skipNext()) { String* s = static_cast<String*>(f->get()); if (s) sdp->addLine("a",*s); } if (addr && m->localCrypto()) { sdp->addLine("a","crypto:" + m->localCrypto()); if (!enc) sdp->addLine("a","encryption:optional"); } }
// Creates a SDP body from transport address and list of media descriptors // Use own list if given media list is 0 MimeSdpBody* SDPSession::createSDP(const char* addr, ObjList* mediaList) { DDebug(m_enabler,DebugAll,"SDPSession::createSDP('%s',%p) [%p]",addr,mediaList,m_ptr); if (!mediaList) mediaList = m_rtpMedia; // if we got no media descriptors we simply create no SDP if (!mediaList) return 0; if (m_sdpSession) ++m_sdpVersion; else m_sdpVersion = m_sdpSession = Time::secNow(); // override the address with the externally advertised if needed if (addr && m_rtpNatAddr) addr = m_rtpNatAddr; if (!m_originAddr) m_originAddr = addr ? addr : m_host.safe(); // no address means on hold or muted String origin; origin << "yate " << m_sdpSession << " " << m_sdpVersion; origin << " "; int f = addIP(origin,m_originAddr); String conn; addIP(conn,addr,f); MimeSdpBody* sdp = new MimeSdpBody; sdp->addLine("v","0"); sdp->addLine("o",origin); sdp->addLine("s",m_parser->m_sessionName); sdp->addLine("c",conn); sdp->addLine("t","0 0"); Lock lock(m_parser); bool defcodecs = m_parser->m_codecs.getBoolValue("default",true); for (ObjList* ml = mediaList->skipNull(); ml; ml = ml->skipNext()) { SDPMedia* m = static_cast<SDPMedia*>(ml->get()); int rfc2833 = 0; if ((m_rfc2833 >= 0) && m->isAudio()) { if (!m_rtpForward) { rfc2833 = m->rfc2833().toInteger(m_rfc2833); if (rfc2833 < 96 || rfc2833 > 127) rfc2833 = 101; } else if (m->rfc2833().toBoolean(true)) { rfc2833 = m->rfc2833().toInteger(); if (rfc2833 < 96 || rfc2833 > 127) rfc2833 = 0; } } String mline(m->fmtList()); ObjList* l = mline.split(',',false); mline = *m; mline << " " << (m->localPort() ? m->localPort().c_str() : "0") << " " << m->transport(); ObjList* map = m->mappings().split(',',false); ObjList rtpmap; ObjList* dest = &rtpmap; String frm; int ptime = 0; ObjList* f = l; for (; f; f = f->next()) { const String* s = static_cast<const String*>(f->get()); if (s) { int mode = 0; if (*s == "g729b") continue; int payload = s->toInteger(SDPParser::s_payloads,-1); int defcode = payload; String tmp = *s; tmp << "="; bool found = false; for (ObjList* pl = map; pl; pl = pl->next()) { const String* mapping = static_cast<const String*>(pl->get()); if (!mapping) continue; if (mapping->startsWith(tmp)) { payload = -1; tmp = *mapping; tmp >> "=" >> payload; found = true; XDebug(m_enabler,DebugAll,"RTP mapped payload %d for '%s' [%p]", payload,s->c_str(),m_ptr); break; } String tmp2 = *mapping; int pload; tmp2 >> "=" >> pload; if (payload == pload) { XDebug(m_enabler,DebugAll,"RTP conflict for payload %d, allocating new [%p]", payload,m_ptr); payload = -1; u_int32_t bmap = 0; for (ObjList* sl = map; sl; sl = sl->next()) { mapping = static_cast<const String*>(sl->get()); if (!mapping) continue; tmp2 = *mapping; pload = 0; tmp2 >> "=" >> pload; if (pload >= 96 && pload < 127) bmap |= 1 << (pload - 96); } // allocate free and non-standard is possible for (pload = 96; pload < 127; pload++) { if (pload == rfc2833) continue; if (lookup(pload,SDPParser::s_rtpmap)) continue; if ((bmap & (1 << (pload - 96))) == 0) { payload = pload; break; } } if (payload >= 0) break; // none free, allocate from "standard" ones too for (pload = 96; pload < 127; pload++) { if (pload == rfc2833) continue; if ((bmap & (1 << (pload - 96))) == 0) { payload = pload; break; } } break; } } if (payload >= 0) { if (!found) { tmp = *s; tmp << "=" << payload; map->append(new String(tmp)); } if (defcode < 0) defcode = payload; const char* map = lookup(defcode,SDPParser::s_rtpmap); if (map && m_parser->m_codecs.getBoolValue(*s,defcodecs && DataTranslator::canConvert(*s))) { if (*s == "ilbc20") ptime = mode = 20; else if (*s == "ilbc30") ptime = mode = 30; frm << " " << payload; String* temp = new String("rtpmap:"); *temp << payload << " " << map; dest = dest->append(temp); if (mode) { temp = new String("fmtp:"); *temp << payload << " mode=" << mode; dest = dest->append(temp); } if (*s == "g729") { temp = new String("fmtp:"); *temp << payload << " annexb=" << ((0 != l->find("g729b")) ? "yes" : "no"); dest = dest->append(temp); } else if (*s == "amr") { temp = new String("fmtp:"); *temp << payload << " octet-align=0"; dest = dest->append(temp); } else if (*s == "amr-o") { temp = new String("fmtp:"); *temp << payload << " octet-align=1"; dest = dest->append(temp); } } } } }
// Create a buffer containing the byte representation of a message to be sent // and another one with the header bool ETSIModem::createMsg(NamedList& params, DataBlock& data) { int type = lookup(params,s_msg); switch (type) { case MsgCallSetup: break; case MsgMWI: case MsgCharge: case MsgSMS: Debug(this,DebugStub,"Create message '%s' not implemented [%p]", params.c_str(),this); return false; default: Debug(this,DebugNote,"Can't create unknown message '%s' [%p]", params.c_str(),this); return false; } ObjList msg; bool fail = !params.getBoolValue("force-send",true); // DateTime - ETSI EN 300 659-3 - 5.4.1 String datetime = params.getValue("datetime"); unsigned char dt[4]; bool ok = false; if (datetime.isBoolean()) if (datetime.toBoolean()) ok = getDateTime(dt); else ; else ok = getDateTime(dt,&datetime); if (ok) { DataBlock* dtParam = new DataBlock(0,10); unsigned char* d = (unsigned char*)dtParam->data(); d[0] = DateTime; d[1] = 8; // Set date and time: %.2d%.2d%.2d%.2d month:day:hour:minute for (int i = 0, j = 2; i < 4; i++, j += 2) { d[j] = '0' + dt[i] / 10; d[j+1] = '0' + dt[i] % 10; } msg.append(dtParam); } else DDebug(this,DebugInfo,"Can't set datetime parameter from '%s' [%p]", datetime.c_str(),this); // CallerId/CallerIdReason - ETSI EN 300 659-3 - 5.4.2: Max caller id 20 // Parameter is missing: append reason (default caller absence: 0x4f: unavailable) int res = appendParam(msg,params,CallerId,20,fail); if (res == -1) return false; if (!res) appendParam(msg,params,CallerIdReason,s_dict_callerAbsence,0x4f); // CallerName/CallerNameReason - ETSI EN 300 659-3 - 5.4.5: Max caller name 50 // Parameter is missing: append reason (default callername absence: 0x4f: unavailable) res = appendParam(msg,params,CallerName,50,fail); if (res == -1) return false; if (!res) appendParam(msg,params,CallerNameReason,s_dict_callerAbsence,0x4f); // Build message unsigned char len = 0; unsigned char hdr[2] = {type}; data.assign(&hdr,sizeof(hdr)); for (ObjList* o = msg.skipNull(); o; o = o->skipNext()) { DataBlock* msgParam = static_cast<DataBlock*>(o->get()); if (len + msgParam->length() > 255) { if (!fail) { Debug(this,DebugNote,"Trucating %s message length to %u bytes [%p]", params.c_str(),data.length(),this); break; } params.setParam("error","message-too-long"); return false; } len += msgParam->length(); data += *msgParam; } if (!len) { params.setParam("error","empty-message"); return false; } unsigned char* buf = ((unsigned char*)(data.data())); buf[1] = len; m_chksum = 0; for (unsigned int i = 0; i < data.length(); i++) m_chksum += buf[i]; unsigned char crcVal = 256 - (m_chksum & 0xff); FSKModem::addRaw(data,&crcVal,1); return true; }