void SIPCall::hangup(int reason) { // Stop all RTP streams stopAllMedia(); if (not inv or not inv->dlg) { removeCall(); throw VoipLinkException("No invite session for this call"); } pjsip_route_hdr *route = inv->dlg->route_set.next; while (route and route != &inv->dlg->route_set) { char buf[1024]; int printed = pjsip_hdr_print_on(route, buf, sizeof(buf)); if (printed >= 0) { buf[printed] = '\0'; RING_DBG("[call:%s] Route header %s", getCallId().c_str(), buf); } route = route->next; } const int status = reason ? reason : inv->state <= PJSIP_INV_STATE_EARLY and inv->role != PJSIP_ROLE_UAC ? PJSIP_SC_CALL_TSX_DOES_NOT_EXIST : inv->state >= PJSIP_INV_STATE_DISCONNECTED ? PJSIP_SC_DECLINE : 0; // Notify the peer terminateSipSession(status); setState(Call::ConnectionState::DISCONNECTED, reason); removeCall(); }
void SIPCall::sendSIPInfo(const char *const body, const char *const subtype) { if (not inv or not inv->dlg) throw VoipLinkException("Couldn't get invite dialog"); pj_str_t methodName = CONST_PJ_STR("INFO"); pjsip_method method; pjsip_method_init_np(&method, &methodName); /* Create request message. */ pjsip_tx_data *tdata; if (pjsip_dlg_create_request(inv->dlg, &method, -1, &tdata) != PJ_SUCCESS) { RING_ERR("[call:%s] Could not create dialog", getCallId().c_str()); return; } /* Create "application/<subtype>" message body. */ pj_str_t content; pj_cstr(&content, body); const pj_str_t type = CONST_PJ_STR("application"); pj_str_t pj_subtype; pj_cstr(&pj_subtype, subtype); tdata->msg->body = pjsip_msg_body_create(tdata->pool, &type, &pj_subtype, &content); if (tdata->msg->body == NULL) pjsip_tx_data_dec_ref(tdata); else pjsip_dlg_send_request(inv->dlg, tdata, getSIPVoIPLink()->getModId(), NULL); }
void SIPCall::peerHungup() { // Stop all RTP streams stopAllMedia(); if (not inv) throw VoipLinkException("No invite session for this call"); terminateSipSession(PJSIP_SC_NOT_FOUND); Call::peerHungup(); }
void SIPCall::sendTextMessage(const std::map<std::string, std::string>& messages, const std::string& /* from */) { if (not inv) throw VoipLinkException("No invite session for this call"); //TODO: for now we ignore the "from" (the previous implementation for sending this info was // buggy and verbose), another way to send the original message sender will be implemented // in the future im::sendSipMessage(inv.get(), messages); }
void IAXVoIPLink::peerHungup(const std::string& id) { IAXCall* call = getIAXCall(id); if (call == NULL) throw VoipLinkException("Could not find call"); Manager::instance().getMainBuffer()->unBindAll(call->getCallId()); call->session = NULL; removeCall(id); }
void IAXVoIPLink::sendRegister(Account *a) { IAXAccount *account = dynamic_cast<IAXAccount*>(a); if (account->getHostname().empty()) throw VoipLinkException("Account hostname is empty"); if (account->getUsername().empty()) throw VoipLinkException("Account username is empty"); ost::MutexLock m(mutexIAX_); if (regSession_) iax_destroy(regSession_); regSession_ = iax_session_new(); if (regSession_) { iax_register(regSession_, account->getHostname().data(), account->getUsername().data(), account->getPassword().data(), 120); nextRefreshStamp_ = time(NULL) + 10; account->setRegistrationState(Trying); } }
void IAXVoIPLink::offhold(const std::string& id) { IAXCall* call = getIAXCall(id); if (call == NULL) throw VoipLinkException("Call does not exist"); Manager::instance().addStream(call->getCallId()); mutexIAX_.enter(); iax_unquelch(call->session); mutexIAX_.leave(); Manager::instance().getAudioDriver()->startStream(); call->setState(Call::ACTIVE); }
void IAXVoIPLink::onhold(const std::string& id) { IAXCall* call = getIAXCall(id); if (call == NULL) throw VoipLinkException("Call does not exist"); Manager::instance().getMainBuffer()->unBindAll(call->getCallId()); mutexIAX_.enter(); iax_quelch_moh(call->session, true); mutexIAX_.leave(); call->setState(Call::HOLD); }
void SIPCall::transfer(const std::string& to) { auto& account = getSIPAccount(); stopRecording(); std::string toUri; pj_str_t dst = { 0, 0 }; toUri = account.getToUri(to); pj_cstr(&dst, toUri.c_str()); RING_DBG("[call:%s] Transferring to %.*s", getCallId().c_str(), (int)dst.slen, dst.ptr); if (!transferCommon(&dst)) throw VoipLinkException("Couldn't transfer"); }
void IAXVoIPLink::hangup(const std::string& id) { IAXCall* call = getIAXCall(id); if (call == NULL) throw VoipLinkException("Could not find call"); Manager::instance().getMainBuffer()->unBindAll(call->getCallId()); mutexIAX_.enter(); iax_hangup(call->session, (char*) "Dumped Call"); mutexIAX_.leave(); call->session = NULL; removeCall(id); }
bool SIPCall::offhold() { bool success = false; auto& account = getSIPAccount(); try { if (account.isStunEnabled()) success = internalOffHold([&] { updateSDPFromSTUN(); }); else success = internalOffHold([] {}); } catch (const SdpException &e) { RING_ERR("[call:%s] %s", getCallId().c_str(), e.what()); throw VoipLinkException("SDP issue in offhold"); } return success; }
void SIPCall::answer() { auto& account = getSIPAccount(); if (not inv) throw VoipLinkException("No invite session for this call"); if (!inv->neg) { RING_WARN("[call:%s] Negotiator is NULL, we've received an INVITE without an SDP", getCallId().c_str()); pjmedia_sdp_session *dummy = 0; getSIPVoIPLink()->createSDPOffer(inv.get(), &dummy); if (account.isStunEnabled()) updateSDPFromSTUN(); } pj_str_t contact(account.getContactHeader(transport_ ? transport_->get() : nullptr)); setContactHeader(&contact); pjsip_tx_data *tdata; if (!inv->last_answer) throw std::runtime_error("Should only be called for initial answer"); // answer with SDP if no SDP was given in initial invite (i.e. inv->neg is NULL) if (pjsip_inv_answer(inv.get(), PJSIP_SC_OK, NULL, !inv->neg ? sdp_->getLocalSdpSession() : NULL, &tdata) != PJ_SUCCESS) throw std::runtime_error("Could not init invite request answer (200 OK)"); // contactStr must stay in scope as long as tdata if (contactHeader_.slen) { RING_DBG("[call:%s] Answering with contact header: %.*s", getCallId().c_str(), (int)contactHeader_.slen, contactHeader_.ptr); sip_utils::addContactHeader(&contactHeader_, tdata); } if (pjsip_inv_send_msg(inv.get(), tdata) != PJ_SUCCESS) { inv.reset(); throw std::runtime_error("Could not send invite request answer (200 OK)"); } setState(CallState::ACTIVE, ConnectionState::CONNECTED); }