Commit 70bc1292 authored by Gabriel Margiani's avatar Gabriel Margiani

call and hangup, buggy.

parent 6a847f33
CXX = g++
CXXFLAGS = -Wall -g -std=c++14 -MD
CXXFLAGS = -Wall -g -std=c++14 -MD -fPIC $(shell pkg-config --cflags libpjproject)
LIBS = -lpthread -lrt
LIBS = -lrt $(shell pkg-config --libs libpjproject)
SRCS = $(wildcard src/*.cpp)
......
/**
* This file is part of 3phone
* Copyright (C) 2015 Gabriel Margiani
*
* 3phone 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 3 of the License, or
* (at your option) any later version.
*
* 3phone 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 3phone. If not, see <http://www.gnu.org/licenses/>.
**/
#include "account.h"
p3::account::account() {};
p3::account::~account() {};
void p3::account::onRegState(pj::OnRegStateParam &prm) {
}
void p3::account::onIncomingCall(pj::OnIncomingCallParam &iprm) {
}
......@@ -25,8 +25,8 @@
namespace p3 {
class account : public pj::Account {
public:
account() {};
~account() {};
account();
~account();
virtual void onRegState(pj::OnRegStateParam &prm);
virtual void onIncomingCall(pj::OnIncomingCallParam &iprm);
......
......@@ -17,15 +17,33 @@
**/
#include "call.h"
#include "sipphone.h"
p3::call::call(p3::account &acc, int call_id) : Call(acc, call_id) {
}
p3::call::call(p3::sipphone &p, p3::account &acc, int call_id) :
Call(acc, call_id),
phone(p)
{}
p3::call::~call() {
}
void p3::call::onCallState(pj::OnCallStateParam& prm) {
pj::CallInfo ci = getInfo();
if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
phone.delete_call(getId());
}
}
void p3::call::onCallMediaState(pj::OnCallMediaStateParam& prm) {
pj::CallInfo ci = getInfo();
for (unsigned i = 0; i < ci.media.size(); i++) {
if (ci.media[i].type==PJMEDIA_TYPE_AUDIO && getMedia(i)) {
pj::AudioMedia *aud_med = static_cast<pj::AudioMedia*>(getMedia(i));
pj::AudDevManager& mgr = pj::Endpoint::instance().audDevManager();
aud_med->startTransmit(mgr.getPlaybackDevMedia());
mgr.getCaptureDevMedia().startTransmit(*aud_med);
}
}
}
......@@ -24,9 +24,14 @@
#include "account.h"
namespace p3 {
class sipphone;
class call : public pj::Call {
p3::sipphone & phone;
public:
call(p3::account& acc, int call_id = PJSUA_INVALID_ID);
call(sipphone& p, account& acc, int call_id = PJSUA_INVALID_ID);
~call();
......
......@@ -27,6 +27,7 @@
std::map<std::string, std::string> p3::client::command_shorthands {
{"c", "call"},
{"h", "hangup"},
{"q", "quit"},
{"x", "exit"}
};
......@@ -103,6 +104,18 @@ void p3::client::run() {
case p3::protocol::ASK_NUMBER:
connection->send(p3::protocol::ANSWER, get_input(m.get_value(), NUMBER));
continue;
case p3::protocol::ASK_ID:
connection->send(p3::protocol::ANSWER, get_input(m.get_value(), ID));
continue;
case p3::protocol::BEGINQTEXT:
m = connection->receive(30);
while (m.get_command() != p3::protocol::ENDQTEXT) {
if (argv.empty()) {
std::cout << m.get_value() << std::endl;
}
m = connection->receive(30);
}
continue;
case p3::protocol::OK:
std::cout << m.get_value() << std::endl;
break;
......
......@@ -38,7 +38,8 @@ namespace p3 {
enum inputType {
COMMAND,
NUMBER
NUMBER,
ID
};
bool interactive;
......
......@@ -98,6 +98,7 @@ void p3::mQueue::send(p3::protocol c, std::string v) {
void p3::mQueue::send(p3::mQueueMessage & qmsg) {
std::string msg = qmsg.get_str();
std::cout << "S: " << key << ": " << msg << std::endl;
timespec tsp;
tsp.tv_sec = time(NULL) + DefaultSendTimeout;
tsp.tv_nsec = 0;
......@@ -130,7 +131,9 @@ p3::mQueueMessage p3::mQueue::receive(int timeout) {
if (ret != -1) {
buf[ret] = '\0';
return p3::mQueueMessage(buf);
p3::mQueueMessage ret(buf);
std::cout << "R: " << key << ": " << ret.get_value() << std::endl;
return ret;
} else {
switch (errno) {
case EINVAL:
......
......@@ -24,6 +24,14 @@ p3::phonebook::phonebook(p3::config& c) : conf(c) {}
std::string p3::phonebook::parse_number(std::string nr) {
std::cout << "parsing Number " << nr << std::endl;
if (nr.find("sip:") != 0) {
nr = "sip:" + nr;
}
if (nr.find('@') == std::string::npos) {
nr += "@" + conf.get_string("phonebook:default_uri");
}
return nr;
}
......@@ -32,6 +32,9 @@ namespace p3 {
ASK,
ASK_NUMBER,
ASK_ID,
BEGINQTEXT,
ENDQTEXT,
ANSWER,
BEGINTEXT,
......
......@@ -33,6 +33,7 @@ std::map<std::string, std::string> p3::server::default_config {
{"account:realm", "*"},
{"account:username", "test"},
{"account:password", "pass"},
{"phonebook:default_uri", "3phone.com"},
};
......@@ -75,12 +76,14 @@ void p3::server::dispatch_thread(std::string id) {
}
void p3::server::server_thread(std::string id) {
phone.register_thread(id);
try {
p3::clientHandler c(id, phone, book);
c.run();
} catch (p3::perror & e) {
std::cout << "Error in client " << id << ": " << e.what() << std::endl;
}
phone.unregister_thread(id);
}
void p3::server::finish_threads() {
......@@ -136,6 +139,8 @@ void p3::clientHandler::run() {
void p3::clientHandler::parse_command(std::string c) {
if ("call" == c) {
handle_call();
} else if ("hangup" == c){
handle_hangup();
} else {
std::cout << "Unknown command received: " << c << std::endl;
connection.send(p3::protocol::ERROR, "Invalid Command '" + c + "'");
......@@ -154,3 +159,33 @@ void p3::clientHandler::handle_call() {
}
connection.send(p3::protocol::OK, "Call OK");
}
void p3::clientHandler::handle_hangup() {
try {
std::cout << phone.get_call_count() << std::endl;
if (phone.get_call_count() > 1) {
send_calls_menu();
connection.send(p3::protocol::ASK_ID, "Call to hangup (id)");
p3::mQueueMessage n = connection.receive(listenTimeout);
phone.hangup(std::stoi(n.get_value()));
} else if (phone.get_call_count() == 1){
phone.hangup(-1);
} else {
connection.send(p3::protocol::ERROR, "No call to Hangup");
return;
}
} catch (p3::perror & e) {
connection.send(p3::protocol::ERROR, e.what());
return;
}
connection.send(p3::protocol::OK, "Hangup OK");
}
void p3::clientHandler::send_calls_menu() {
std::map<int, std::string> cl = phone.get_call_list();
connection.send(p3::protocol::BEGINQTEXT, "Call list");
for (auto c : cl) {
connection.send(p3::protocol::TEXT, std::to_string(c.first) + " " + c.second);
}
connection.send(p3::protocol::ENDQTEXT, "Call list");
}
......@@ -70,6 +70,9 @@ namespace p3 {
void parse_command(std::string c);
void handle_call();
void handle_hangup();
void send_calls_menu();
public:
clientHandler(std::string i, sipphone & p, phonebook & b);
......
......@@ -21,7 +21,7 @@
#include "error.h"
#include "sipphone.h"
p3::sipphone::sipphone(p3::config& c) : conf(c) {
p3::sipphone::sipphone(p3::config& c) : conf(c), active_call(-1) {
// Initiate pj
endpoint = new pj::Endpoint;
......@@ -35,6 +35,7 @@ p3::sipphone::sipphone(p3::config& c) : conf(c) {
pj::EpConfig ep_cfg;
ep_cfg.logConfig.level = conf.get_int("pj:log_level");
ep_cfg.uaConfig.maxCalls = conf.get_int("pj:max_calls");
ep_cfg.uaConfig.userAgent = "3phone, (c) 2015 Gabriel Margiani";
//ep_cfg.mediaConfig.sndClockRate = 16000;
endpoint->libInit(ep_cfg);
} catch(pj::Error& error) {
......@@ -44,7 +45,8 @@ p3::sipphone::sipphone(p3::config& c) : conf(c) {
try {
pj::TransportConfig tcfg;
tcfg.port = 5060;
pj::TransportId tid = endpoint->transportCreate(PJSIP_TRANSPORT_TCP, tcfg);
//pj::TransportId tid =
endpoint->transportCreate(PJSIP_TRANSPORT_UDP, tcfg);
} catch(pj::Error& error) {
throw p3::perror("sipphone: pjInit: Transport creation error", error.info());
}
......@@ -58,14 +60,14 @@ p3::sipphone::sipphone(p3::config& c) : conf(c) {
pj::AccountConfig acc_cfg;
acc_cfg.idUri = conf.get_string("account:id_uri");
acc_cfg.regConfig.registrarUri = conf.get_string("accout:registrar");
acc_cfg.regConfig.registrarUri = conf.get_string("account:registrar");
acc_cfg.sipConfig.authCreds.push_back(
pj::AuthCredInfo(
conf.get_string("accout:sheme"),
conf.get_string("accout:realm"),
conf.get_string("accout:username"),
conf.get_string("account:sheme"),
conf.get_string("account:realm"),
conf.get_string("account:username"),
0,
conf.get_string("accout:password")
conf.get_string("account:password")
)
);
acc = new p3::account;
......@@ -77,24 +79,92 @@ p3::sipphone::sipphone(p3::config& c) : conf(c) {
}
}
p3::sipphone::~sipphone() {
calls_mutex.lock();
for (auto c : calls) {
delete c.second;
}
calls_mutex.unlock();
threads_mutex.lock();
for (auto t : pj_threads) {
delete [] t.second.second;
pj_threads.erase(t.first);
}
threads_mutex.lock();
endpoint->libDestroy();
delete acc;
delete endpoint;
for (auto c : calls) {
delete c;
}
}
void p3::sipphone::register_thread(std::string id) {
std::lock_guard<std::mutex> g(threads_mutex);
pj_thread_desc* ptd = new pj_thread_desc[1];
pj_thread_t* tptr;
std::cout << "registering " << id << std::endl;
pj_thread_register(id.c_str(), *ptd, &tptr);
pj_threads[id] = { tptr, ptd };
}
void p3::sipphone::unregister_thread(std::string id) {
std::lock_guard<std::mutex> g(threads_mutex);
std::cout << "unregistering " << id << std::endl;
pj_thread_destroy(pj_threads[id].first);
}
void p3::sipphone::call(std::string& nr) {
std::cout << "calling " << nr << std::endl;
p3::call* c = new p3::call(*acc);
p3::call* c = new p3::call(*this, *acc);
pj::CallOpParam prm(true); // Use default call settings
calls.push_back(c);
calls_mutex.lock();
active_call = c->getId();
std::cout << "calling " << c->getId() << std::endl;
calls[c->getId()] = c;
calls_mutex.unlock();
try {
c->makeCall(nr, prm);
} catch(pj::Error& err) {
throw p3::perror("sipphone:call", "error calling " + nr + " " + err.info());
}
}
void p3::sipphone::hangup(int id) {
std::lock_guard<std::mutex> g(calls_mutex);
if (id == -1) id = active_call;
std::cout << "hangup call " << id << std::endl;
if (calls.count(id) == 1) {
pj::CallOpParam o;
try {
calls[id]->hangup(o);
} catch (pj::Error &e) {
throw p3::perror("sipphone:pjhangup", e.info());
}
} else {
throw p3::perror("sipphone:hangup", "Invalide id " + std::to_string(id));
}
}
void p3::sipphone::delete_call(int in) {
std::cout << "delete call " << in << std::endl;
std::lock_guard<std::mutex> g(calls_mutex);
delete calls[in];
calls.erase(in);
if (in == active_call) {
if (!calls.empty()) {
active_call = calls.begin()->first;
} else {
active_call = -1;
}
}
}
int p3::sipphone::get_call_count() {
return calls.size();
}
std::map<int, std::string> p3::sipphone::get_call_list() {
std::map<int, std::string> s;
std::lock_guard<std::mutex> g(calls_mutex);
for (auto a : calls) {
s[a.first] = a.second->getInfo().remoteUri;
}
return s;
}
......@@ -20,7 +20,9 @@
#define __P3_SIPPHONE_H__
#include <string>
#include <list>
#include <map>
#include <mutex>
#include <atomic>
#include <pjsua2.hpp>
......@@ -37,7 +39,12 @@ namespace p3 {
pj::Endpoint* endpoint;
p3::account* acc;
std::list<p3::call *> calls;
std::atomic_int active_call;
std::map<int, p3::call *> calls;
std::mutex calls_mutex;
std::map<std::string, std::pair<pj_thread_t*, pj_thread_desc*> > pj_threads;
std::mutex threads_mutex;
public:
......@@ -45,7 +52,17 @@ namespace p3 {
sipphone(const sipphone& c) = delete;
~sipphone();
void register_thread(std::string id);
void unregister_thread(std::string id);
void call(std::string& nr);
void hangup(int id = -1);
void delete_call(int id); // Call has been terminated and needs to be removed from list.
int get_call_count();
std::map<int, std::string> get_call_list();
};
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment