📄 session.cpp
字号:
// Copyright (C) 2005 Open Source Telecom Corp.// // 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.#include "driver.h"namespace sipdriver {using namespace ost;using namespace std;Session::Session(timeslot_t ts) :BayonneSession(&Driver::sip, ts),TimerPort(){#ifndef WIN32 if(getppid() > 1) logevents = &cout;#endif iface = IF_INET; bridge = BR_GATE; cid = 0; did = 0; rtp = NULL; dtmf_sipinfo = Driver::sip.info_negotiate; dtmf_payload = Driver::sip.dtmf_negotiate; data_payload = Driver::sip.data_negotiate; dtmf_inband = Driver::sip.dtmf_inband; dtmf_sipinfo = false; update_pos = false; peer_buffer = NULL; peer_codec = NULL; if(Driver::peer_encoding == Audio::pcm16Mono) { peer_buffer = new Sample[Driver::sip.info.framecount]; peer_codec = AudioCodec::getCodec(Driver::sip.info); } }Session::~Session(){}void Session::setEncoding(const char *encoding, timeout_t framing){ if(codec) AudioCodec::endCodec(codec); memset(&info, 0, sizeof(info)); info.encoding = Audio::getEncoding(encoding); switch(info.encoding) { default: info.rate = Audio::rate8khz; if(!framing) framing = 20; } info.setFraming(framing); codec = AudioCodec::getCodec(info);}void Session::sendDTMFInfo(char digit, unsigned duration){ osip_message_t *message = NULL; char dtmf_body[1000]; snprintf(dtmf_body, sizeof(dtmf_body) - 1, "Signal=%c\r\nDuration=%d\r\n", digit, duration); eXosip_lock(); if(eXosip_call_build_info(did, &message) != 0) { eXosip_unlock(); return; } osip_message_set_body(message, dtmf_body, strlen(dtmf_body)); osip_message_set_content_type(message, "application/dtmf-relay"); eXosip_call_send_request(did, message); eXosip_unlock();}timeout_t Session::getRemaining(void){ return TimerPort::getTimer();}void Session::startTimer(timeout_t timer){ TimerPort::setTimer(timer); msgport->update();}void Session::stopTimer(void){ TimerPort::endTimer(); msgport->update();}tpport_t Session::getLocalPort(void){ Driver *d = (Driver *)(driver); return d->rtp_port + (4 * timeslot);} void Session::startRTP(void){ if(rtp) { slog.error("%s: rtp already started", logname); return; } rtp = new RTPStream(this); if(!rtp->addDestination(remote_address, remote_port)) slog.error("%s: destination not available"); rtp->start();} void Session::stopRTP(void){ if(!rtp) return; rtp->setSource(NULL); rtp->setSink(NULL); rtp->setTone(NULL); delete rtp; rtp = NULL;}void Session::makeIdle(void){ update_pos = false; if(offhook) sipHangup(); BayonneSession::makeIdle(); dtmf_inband = Driver::sip.dtmf_inband; dtmf_payload = Driver::sip.dtmf_negotiate; dtmf_sipinfo = Driver::sip.info_negotiate; data_payload = Driver::sip.data_negotiate; memcpy(&info, &Driver::sip.info, sizeof(info)); if(codec) AudioCodec::endCodec(codec); codec = AudioCodec::getCodec(info);}bool Session::enterJoin(Event *event){ Level level = 26000; Rate rate = (Rate)info.rate; unsigned f1, f2; timeout_t framing = getToneFraming(), duration; struct dtmf2833 dtmfevent; switch(event->id) { case AUDIO_IDLE: rtp->setTone(NULL); return true; case DTMF_GENTONE: if(dtmf_sipinfo) { sendDTMFInfo(getChar(event->dtmf.digit), event->dtmf.duration); return true; } if(dtmf_payload) { memset(&dtmfevent, 0, sizeof(dtmfevent)); dtmfevent.event = event->dtmf.digit; rtp->set2833(&dtmfevent, event->dtmf.duration); return true; } rtp->setTone(NULL); if(audio.tone) { delete audio.tone; audio.tone = NULL; } f1 = f2 = 0; duration = event->dtmf.duration; duration = (duration + (framing - 1)) / framing; duration *= framing; switch(event->dtmf.digit) { case 0: f1 = 941; f2 = 1336; break; case 1: f1 = 697; f2 = 1209; break; case 2: f1 = 697; f2 = 1336; break; case 3: f1 = 697; f2 = 1447; break; case 4: f1 = 770; f2 = 1209; break; case 5: f1 = 770; f2 = 1336; break; case 6: f1 = 770; f2 = 1477; break; case 7: f1 = 852; f2 = 1209; break; case 8: f1 = 852; f2 = 1336; break; case 9: f1 = 852; f2 = 1477; break; case 10: f1 = 941; f2 = 1209; break; case 11: f1 = 941; f2 = 1477; break; } if(f1) audio.tone = new AudioTone(f1, f2, level, level, duration, rate); if(audio.tone) rtp->setTone(audio.tone); return true; default: return false; }}bool Session::enterSeize(Event *event){ char buf[128]; char cref[64]; const char *cp, *to, *from = NULL; char *sp = NULL; osip_message_t *invite = NULL; Registry *reg = NULL; ScriptImage *img = getImage(); char rbuf[16]; char cbuf[65]; char sdp[512]; const char *rtpmap = NULL; const char *route; const char *lp = driver->getLast("localip"); BayonneSession *parent = Bayonne::getSid(var_pid); switch(event->id) { case ENTER_STATE: cp = getSymbol("session.dialed"); if(!cp) { event->id = DIAL_FAILED; return false; } route = Driver::sip.getLast("outbound"); if(!strchr(cp, '@')) { snprintf(buf, sizeof(buf), "uri.%s", cp); reg = (Registry *)img->getPointer(buf); if(reg && !strnicmp(reg->type, "ext", 3)) { snprintf(buf, sizeof(buf), "sip:%s@%s", reg->userid, reg->proxy); if(!route) route = reg->proxy; sp = strrchr(buf, ':'); if(sp && !stricmp(sp, ":5060")) *sp = 0; setConst("session.uri_remote", buf); goto dialing; } } if(!strchr(cp, '@')) snprintf(buf, sizeof(buf), "sip:%s@%s", cp, route); else { if(!strnicmp(cp, "sip:", 4)) cp += 4; snprintf(buf, sizeof(buf), "sip:%s", cp); } if(sp && stricmp(sp, ":5060")) sp = NULL; setConst("session.uri_remote", buf); cp = getSymbol("session.uri_remote"); cp = strchr(cp, '@'); if(cp) { snprintf(buf, sizeof(buf), "sip.%s", ++cp); reg = (Registry *)img->getPointer(buf); }dialing: dtmf_sipinfo = Driver::sip.info_negotiate; if(reg) { if(reg->dtmf && !stricmp(reg->dtmf, "info")) dtmf_sipinfo = true; else if(reg->dtmf && !stricmp(reg->dtmf, "sipinfo")) dtmf_sipinfo = true; else if(reg->dtmf) dtmf_sipinfo = false; if(!route) route = reg->proxy; snprintf(rbuf, sizeof(rbuf), "sipreg.%d", reg->regid); setConst("session.registry", rbuf); setConst("session.uri_server", reg->proxy); setConst("session.uri_local", reg->contact); if(reg->address) { InetAddress host(reg->address); snprintf(cbuf, sizeof(cbuf), "%s", inet_ntoa(host.getAddress())); setConst("session.ip_public", cbuf); } else setConst("session.ip_public", lp); } else { snprintf(buf, sizeof(buf), "sip:anon@%s", Driver::sip.getLast("interface")); setConst("session.uri_local", buf); setConst("session.ip_local", lp); setConst("session.ip_public", lp); } to = getSymbol("session.uri_remote"); from = getSymbol("session.uri_local"); if(!route) { route = strchr(to, '@'); if(route) ++route; } if(!strnicmp(route, "sip:", 4)) route += 4; snprintf(buf, sizeof(buf), "<sip:%s;lr>", route); slog.debug("invite %s from %s using %s", to, from, route); eXosip_lock(); if(eXosip_call_build_initial_invite(&invite, (char *)to, (char *)from, buf, "Bayonne Call")) { eXosip_unlock();failure: slog.error("sip: invite invalid"); event->id = DIAL_FAILED; return false; } eXosip_unlock(); cp = Driver::sip.getLast("localip"); data_payload = Driver::sip.data_negotiate; dtmf_payload = Driver::sip.dtmf_negotiate; if(parent && !parent->peerLinear()) setEncoding(parent->audioEncoding(), parent->audioFraming()); else if(reg && reg->encoding) setEncoding(reg->encoding, reg->framing); switch(info.encoding) { case pcm16Stereo: data_payload = 98; rtpmap = "a=rtpmap:98 L16/11025/2"; break; case pcm16Mono: data_payload = 97; rtpmap = "a=rtpmap:97 L16/8000/1"; break; case pcm8Mono: data_payload = 96; rtpmap = "a=rtpmap:96 L8/8000/1"; break; case mulawAudio: data_payload = 0; rtpmap = "a=rtpmap:0 PCMU/8000/1"; break; case alawAudio: data_payload = 8; rtpmap = "a=rtpmap:8 PCMA/8000/1"; break; case gsmVoice: data_payload = 3; rtpmap = "a=rtpmap:3 GSM/8000/1"; break; case speexVoice: data_payload = 97; rtpmap = "a=rtpmap:97 SPEEX/8000/1"; default: break; } if(dtmf_payload) snprintf(sdp, sizeof(sdp), "v=0\r\n" "o=bayonne 0 0 IN IP4 %s\r\n" "s=call\r\n" "c=IN IP4 %s\r\n" "t=0 0\r\n" "m=audio %d RTP/AVP %d %d\r\n" "%s\r\n" "a=rtpmap:%d telephone-events/8000\r\n", cp, cp, getLocalPort(), data_payload, dtmf_payload, rtpmap, dtmf_payload); else snprintf(sdp, sizeof(sdp), "v=0\r\n" "o=bayonne 0 0 IN IP4 %s\r\n" "s=call\r\n" "c=IN IP4 %s\r\n" "t=0 0\r\n" "m=audio %d RTP/AVP %d\r\n" "%s\r\n", cp, cp, getLocalPort(), data_payload, rtpmap); setConst("session.rtpmap", rtpmap); if(dtmf_sipinfo) setConst("session.dtmfmode", "info"); else if(dtmf_payload) setConst("session.dtmfmode", "2833"); else setConst("session.dtmfmode", "none"); eXosip_lock(); osip_message_set_body(invite, sdp, strlen(sdp)); osip_message_set_content_type(invite, "application/sdp"); offhook = true; setSid(); snprintf(cref, sizeof(cref), "%s@%s", var_sid, inet_ntoa(local_address.getAddress())); setConst("session.callref", cref); cid = eXosip_call_send_initial_invite(invite); if(cid > 0) eXosip_call_set_reference(cid, cref); eXosip_unlock(); if(cid <= 0) goto failure; startTimer(atol(Driver::sip.getLast("invite"))); return true; case CALL_CONNECTED: startRTP(); setRunning(); return true; case CALL_ANSWERED: setState(STATE_PICKUP); return true; case CALL_RINGING: stopTimer(); return true; case TIMER_EXPIRED: offhook = false; default: return false; }}bool Session::enterHangup(Event *event){ switch(event->id) { case TIMER_EXPIRED: sipHangup(); default: break; } update_pos = false; return false;}bool Session::enterRecord(Event *event){ switch(event->id) { case ENTER_STATE: audio.record(state.audio.list[0], state.audio.mode, state.audio.note); update_pos = true; if(!audio.isOpen()) { slog.error("%s: audio file access error", logname); error("no-files"); setRunning(); return true; } rtp->setSink(&audio, state.audio.total); return false; default: return false; }}bool Session::enterPlay(Event *event){ switch(event->id) { case AUDIO_IDLE: if(!Driver::sip.audio_timer) return false; startTimer(Driver::sip.audio_timer); return true; case ENTER_STATE: if(state.audio.mode == Audio::modeReadAny) update_pos = false; else update_pos = true; audio.play(state.audio.list, state.audio.mode); if(!audio.isOpen()) { slog.error("%s: audio file access error", logname); error("no-files"); setRunning(); return true; } rtp->setSource(&audio); return false; default: return false; }}bool Session::enterPickup(Event *event){ if(event->id == ENTER_STATE) { offhook = true; startRTP(); startTimer(driver->getPickupTimer()); return true; } else if(event->id == CALL_ACCEPTED) { startTimer(Driver::sip.accept_timer); return true; } return false;}bool Session::enterTone(Event *event){ if(event->id == ENTER_STATE && audio.tone) rtp->setTone(audio.tone); return false;}bool Session::enterXfer(Event *event){ osip_message_t *refer; int rtn; switch(event->id) { case DIAL_FAILED: event->id = DIAL_INVALID; return false; case ENTER_STATE: eXosip_lock(); eXosip_call_build_refer(did, (char *)state.url.ref, &refer); rtn = eXosip_call_send_request(did, refer); eXosip_unlock(); if(!rtn) return true; event->errmsg = "transfer-invalid"; event->id = ERROR_STATE; return false; case STOP_DISCONNECT: setState(STATE_HANGUP); return true; default: return false; } }void Session::clrAudio(void){ if(rtp) { rtp->setSource(NULL); rtp->setTone(NULL); } if(audio.isOpen() && update_pos) { audio.getPosition(audio.var_position, 12); update_pos = false; } audio.cleanup();}void Session::sipHangup(void){ eXosip_lock(); eXosip_call_terminate(cid, did); eXosip_unlock(); stopRTP(); offhook = false;}timeout_t Session::getToneFraming(void){ return info.framing;}const char *Session::audioExtension(void){ return Audio::getExtension(info.encoding);}timeout_t Session::audioFraming(void){ return info.framing;}const char *Session::audioEncoding(void){ return Audio::getName(info.encoding);}const char *Session::checkAudio(bool live){ audio.libext = ".au"; switch(info.encoding) { case alawAudio: audio.libext = ".al"; break; case gsmVoice: if(!audio.extension) audio.extension = ".gsm"; audio.libext = ".gsm"; default: break; } if(!audio.extension) audio.extension = ".au"; if(audio.encoding == unknownEncoding) audio.encoding = info.encoding; if(!live) { if(!audio.framing) audio.framing = 10; return NULL; } audio.framing = info.framing; if(audio.encoding != info.encoding) return "unsupported audio format"; return NULL;} bool Session::peerAudio(Encoded encoded){ enter(); if(!peer || !rtp || rtp->source || !isJoined()) { leave(); return false; } rtp->peerAudio(encoded, peer->peerLinear()); leave(); return true;} } // namespace
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -