1-2 次调用后,pjsua2 在 makeCall() 处挂起
pjsua2 hangs at makeCall() after 1-2 calls
我开始用 Qt5 编写应用程序,Im 运行 pjsua2_demo.cpp 来自 pjproject-2.9/pjsip-apps/src/samples/ 在一个带有无限 while(1) 循环的 QThread 中离开 pjsua2 运行永远。
当我在此处的 makeCall() 函数中进行 1-2 次调用时 blocks/hangs:
call->makeCall(num.toStdString(), prm);
另外我想知道我写的代码是否正确。 :)
这是我的mainwindow.cpp
#include "./ui_mainwindow.h"
#include "pjsuathread.h"
PjsuaThread *pjsua_thread;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
pjsua_thread = new PjsuaThread(this);
connect(pjsua_thread, &PjsuaThread::resultReady, this, &MainWindow::handleResults);
connect(pjsua_thread, &PjsuaThread::resultReady2, this, &MainWindow::handleResults2);
connect(pjsua_thread, &PjsuaThread::finished, pjsua_thread, &QObject::deleteLater);
pjsua_thread->start();
ui->answerButton->setVisible(false);
ui->hangButton->setVisible(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::handleResults(const QString &s)
{
ui->textEdit->setText(s);
}
void MainWindow::handleResults2(const QString &ss)
{
if(ss=="ringing")
{
ui->answerButton->setVisible(true);
ui->hangButton->setVisible(true);
}
}
void MainWindow::on_callButton_clicked()
{
pjsua_thread->number = "sip:2010@192.168.0.44";
pjsua_thread->state = "call";
ui->hangButton->setVisible(true);
}
void MainWindow::on_callButton2_clicked()
{
pjsua_thread->number = "sip:1001@192.168.0.44";
pjsua_thread->state = "call";
ui->hangButton->setVisible(true);
}
void MainWindow::on_hangButton_clicked()
{
pjsua_thread->state = "hangup";
ui->hangButton->setVisible(false);
ui->answerButton->setVisible(false);
}
void MainWindow::on_answerButton_clicked()
{
pjsua_thread->state = "answer";
ui->hangButton->setVisible(true);
ui->answerButton->setVisible(false);
}
这是我的pjsuathread.cpp
#include <QString>
#include "pjsuathread.h"
#include "pjsua2_main.h"
PjsuaThread *pjt = NULL;
PjsuaThread::PjsuaThread(QObject *parent)
: QThread{parent}
{
pjt = this;
}
void PjsuaThread::run()
{
pjsua2_main();
}
这是我的 pjsua2_main.cpp
#include "pjsua2_main.h"
#include <pjsua2.hpp>
#include <iostream>
#include <pj/file_access.h>
#define THIS_FILE "pjsua2_main.cpp"
using namespace pj;
Call *call = NULL;
class MyAccount;
class MyCall : public Call
{
private:
MyAccount *myAcc;
public:
MyCall(Account &acc, int call_id = PJSUA_INVALID_ID)
: Call(acc, call_id)
{
myAcc = (MyAccount *)&acc;
}
~MyCall()
{
}
virtual void onCallState(OnCallStateParam &prm);
virtual void onCallTransferRequest(OnCallTransferRequestParam &prm);
virtual void onCallReplaced(OnCallReplacedParam &prm);
virtual void onCallMediaState(OnCallMediaStateParam &prm);
};
class MyAccount : public Account
{
public:
std::vector<Call *> calls;
public:
MyAccount()
{}
~MyAccount()
{
std::cout << "*** Account is being deleted: No of calls="
<< calls.size() << std::endl;
for (std::vector<Call *>::iterator it = calls.begin();
it != calls.end(); )
{
delete (*it);
it = calls.erase(it);
}
}
void removeCall(Call *call)
{
for (std::vector<Call *>::iterator it = calls.begin();
it != calls.end(); ++it)
{
if (*it == call) {
calls.erase(it);
break;
}
}
}
virtual void onRegState(OnRegStateParam &prm)
{
AccountInfo ai = getInfo();
std::cout << (ai.regIsActive? "*** Register: code=" : "*** Unregister: code=")
<< prm.code << std::endl;
}
virtual void onIncomingCall(OnIncomingCallParam &iprm)
{
call = new MyCall(*this, iprm.callId);
CallInfo ci = call->getInfo();
std::cout << "*** Incoming Call: " << ci.remoteUri << " ["
<< ci.stateText << "]" << std::endl;
emit pjt->resultReady2("ringing");
calls.push_back(call);
}
};
void MyCall::onCallState(OnCallStateParam &prm)
{
PJ_UNUSED_ARG(prm);
CallInfo ci = getInfo();
std::cout << "*** Call: " << ci.remoteUri << " [" << ci.stateText << "]" << std::endl;
pjt->info+="*** Call: ";
pjt->info+=QString::fromStdString(ci.remoteUri);
pjt->info+=" [";
pjt->info+=QString::fromStdString(ci.stateText);
pjt->info+="]\n";
pjt->infoChanged=true;
if (ci.state == PJSIP_INV_STATE_DISCONNECTED)
{
//pjt->remove_call=true;
myAcc->removeCall(this);
/* Delete the call */
delete this;
}
}
void MyCall::onCallMediaState(OnCallMediaStateParam &prm)
{
//PJ_UNUSED_ARG(prm);
CallInfo ci = getInfo();
AudioMedia aud_med;
try {
// Get the first audio media
aud_med = getAudioMedia(-1);
} catch(...) {
std::cout << "Failed to get audio media" << std::endl;
return;
}
AudioMedia& play_dev_med = Endpoint::instance().audDevManager().getPlaybackDevMedia();
AudioMedia& cap_dev_med = Endpoint::instance().audDevManager().getCaptureDevMedia();
pjt->info+="*** Connecting audio streams *** \n";
pjt->infoChanged=true;
// This will connect the sound device/mic to the call audio media
cap_dev_med.startTransmit(aud_med);
// And this will connect the call audio media to the sound device/speaker
aud_med.startTransmit(play_dev_med);
}
void MyCall::onCallTransferRequest(OnCallTransferRequestParam &prm)
{
/* Create new Call for call transfer */
prm.newCall = new MyCall(*myAcc);
}
void MyCall::onCallReplaced(OnCallReplacedParam &prm)
{
/* Create new Call for call replace */
prm.newCall = new MyCall(*myAcc, prm.newCallId);
}
MyAccount *acc(new MyAccount);
void make_call(QString num)
{
if(pjt->remove_call)
{
acc->removeCall(call);
/* Delete the call */
delete call;
pjt->remove_call=true;
}
std::cout << "here 1" << std::endl;
// Make outgoing call
call = new MyCall(*acc);
std::cout << "here 2" << std::endl;
acc->calls.push_back(call);
std::cout << "here 3" << std::endl;
CallOpParam prm(true);
std::cout << "here 4" << std::endl;
prm.opt.audioCount = 1;
prm.opt.videoCount = 0;
std::cout << "here 5" << std::endl;
call->makeCall(num.toStdString(), prm);
std::cout << "here 6" << std::endl;
}
static void mainProg1(Endpoint &ep)
{
// Init library
EpConfig ep_cfg;
ep_cfg.logConfig.level = 4;
ep_cfg.medConfig.threadCnt = 2;
ep.libInit( ep_cfg );
// Transport
TransportConfig tcfg;
tcfg.port = 5080;
ep.transportCreate(PJSIP_TRANSPORT_UDP, tcfg);
// Start library
ep.libStart();
std::cout << "*** PJSUA2 STARTED ***" << std::endl;
pjt->info="*** PJSUA2 STARTED ***\n";
emit pjt->resultReady(pjt->info);
// Add account
AccountConfig acc_cfg;
acc_cfg.idUri = "sip:2033@192.168.0.44";
acc_cfg.regConfig.registrarUri = "sip:192.168.0.44";
acc_cfg.sipConfig.authCreds.push_back( AuthCredInfo("digest", "*", "2033", 0, "PAss1234") );
try {
acc->create(acc_cfg);
} catch (...) {
std::cout << "Adding account failed" << std::endl;
}
//pj_thread_sleep(2000);
//make_call();
while(1)
{
if(pjt->state=="call")
{
pjt->state="";
std::cout << "############################# CALL ############################" << std::endl;
make_call(pjt->number);
std::cout << "###############################################################" << std::endl;
}
else if(pjt->state=="answer")
{
pjt->state="";
CallOpParam prm;
prm.statusCode = (pjsip_status_code)200;
call->answer(prm);
}
else if(pjt->state=="hangup")
{
pjt->state="";
CallOpParam prm;
prm.statusCode = (pjsip_status_code)486;
call->hangup(prm);
//ep.hangupAllCalls();
}
else if(pjt->infoChanged)
{
pjt->infoChanged=false;
emit pjt->resultReady(pjt->info);
}
else if(pjt->remove_call)
{
pjt->info+="Removing call...\n";
pjt->infoChanged=true;
acc->removeCall(call);
/* Delete the call */
delete call;
pjt->remove_call=false;
}
//ep.libHandleEvents(60);
}
// Hangup all calls
// pj_thread_sleep(4000);
// ep.hangupAllCalls();
// pj_thread_sleep(4000);
//
// Destroy library
std::cout << "*** PJSUA2 SHUTTING DOWN ***" << std::endl;
delete acc; /* Will delete all calls too */
}
int pjsua2_main()
{
int ret = 0;
Endpoint ep;
try {
ep.libCreate();
mainProg1(ep);
ret = PJ_SUCCESS;
} catch (Error & err) {
std::cout << "Exception: " << err.info() << std::endl;
ret = 1;
}
try {
ep.libDestroy();
} catch(Error &err) {
std::cout << "Exception: " << err.info() << std::endl;
ret = 1;
}
if (ret == PJ_SUCCESS) {
std::cout << "Success" << std::endl;
} else {
std::cout << "Error Found" << std::endl;
}
return ret;
}
这些是我的头文件:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
public slots:
void handleResults(const QString &s);
void handleResults2(const QString &ss);
private slots:
void on_callButton_clicked();
void on_callButton2_clicked();
void on_hangButton_clicked();
void on_answerButton_clicked();
};
#endif // MAINWINDOW_H
pjsuathread.h
#ifndef PJSUATHREAD_H
#define PJSUATHREAD_H
#include <QThread>
class PjsuaThread : public QThread
{
Q_OBJECT
public:
explicit PjsuaThread(QObject *parent = nullptr);
void run() override;
QString state;
QString info;
QString number;
bool infoChanged=false;
bool ringing=false;
bool remove_call=false;
signals:
void resultReady(const QString &s);
void resultReady2(const QString &ss);
};
#endif // PJSUATHREAD_H
和
pjsua2_main.h
#ifndef PJSUA2_MAIN_H
#define PJSUA2_MAIN_H
#include "pjsuathread.h"
int pjsua2_main();
extern PjsuaThread *pjt;
#endif // PJSUA2_MAIN_H
我解决了这个问题,
它是 pjproject 的版本。
现在我尝试使用 v2.10,一切正常。
v2.12 和 v2.11 不起作用,因为它们在我编译演示应用程序时给我未定义的引用。
我开始用 Qt5 编写应用程序,Im 运行 pjsua2_demo.cpp 来自 pjproject-2.9/pjsip-apps/src/samples/ 在一个带有无限 while(1) 循环的 QThread 中离开 pjsua2 运行永远。
当我在此处的 makeCall() 函数中进行 1-2 次调用时 blocks/hangs:
call->makeCall(num.toStdString(), prm);
另外我想知道我写的代码是否正确。 :)
这是我的mainwindow.cpp
#include "./ui_mainwindow.h"
#include "pjsuathread.h"
PjsuaThread *pjsua_thread;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
pjsua_thread = new PjsuaThread(this);
connect(pjsua_thread, &PjsuaThread::resultReady, this, &MainWindow::handleResults);
connect(pjsua_thread, &PjsuaThread::resultReady2, this, &MainWindow::handleResults2);
connect(pjsua_thread, &PjsuaThread::finished, pjsua_thread, &QObject::deleteLater);
pjsua_thread->start();
ui->answerButton->setVisible(false);
ui->hangButton->setVisible(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::handleResults(const QString &s)
{
ui->textEdit->setText(s);
}
void MainWindow::handleResults2(const QString &ss)
{
if(ss=="ringing")
{
ui->answerButton->setVisible(true);
ui->hangButton->setVisible(true);
}
}
void MainWindow::on_callButton_clicked()
{
pjsua_thread->number = "sip:2010@192.168.0.44";
pjsua_thread->state = "call";
ui->hangButton->setVisible(true);
}
void MainWindow::on_callButton2_clicked()
{
pjsua_thread->number = "sip:1001@192.168.0.44";
pjsua_thread->state = "call";
ui->hangButton->setVisible(true);
}
void MainWindow::on_hangButton_clicked()
{
pjsua_thread->state = "hangup";
ui->hangButton->setVisible(false);
ui->answerButton->setVisible(false);
}
void MainWindow::on_answerButton_clicked()
{
pjsua_thread->state = "answer";
ui->hangButton->setVisible(true);
ui->answerButton->setVisible(false);
}
这是我的pjsuathread.cpp
#include <QString>
#include "pjsuathread.h"
#include "pjsua2_main.h"
PjsuaThread *pjt = NULL;
PjsuaThread::PjsuaThread(QObject *parent)
: QThread{parent}
{
pjt = this;
}
void PjsuaThread::run()
{
pjsua2_main();
}
这是我的 pjsua2_main.cpp
#include "pjsua2_main.h"
#include <pjsua2.hpp>
#include <iostream>
#include <pj/file_access.h>
#define THIS_FILE "pjsua2_main.cpp"
using namespace pj;
Call *call = NULL;
class MyAccount;
class MyCall : public Call
{
private:
MyAccount *myAcc;
public:
MyCall(Account &acc, int call_id = PJSUA_INVALID_ID)
: Call(acc, call_id)
{
myAcc = (MyAccount *)&acc;
}
~MyCall()
{
}
virtual void onCallState(OnCallStateParam &prm);
virtual void onCallTransferRequest(OnCallTransferRequestParam &prm);
virtual void onCallReplaced(OnCallReplacedParam &prm);
virtual void onCallMediaState(OnCallMediaStateParam &prm);
};
class MyAccount : public Account
{
public:
std::vector<Call *> calls;
public:
MyAccount()
{}
~MyAccount()
{
std::cout << "*** Account is being deleted: No of calls="
<< calls.size() << std::endl;
for (std::vector<Call *>::iterator it = calls.begin();
it != calls.end(); )
{
delete (*it);
it = calls.erase(it);
}
}
void removeCall(Call *call)
{
for (std::vector<Call *>::iterator it = calls.begin();
it != calls.end(); ++it)
{
if (*it == call) {
calls.erase(it);
break;
}
}
}
virtual void onRegState(OnRegStateParam &prm)
{
AccountInfo ai = getInfo();
std::cout << (ai.regIsActive? "*** Register: code=" : "*** Unregister: code=")
<< prm.code << std::endl;
}
virtual void onIncomingCall(OnIncomingCallParam &iprm)
{
call = new MyCall(*this, iprm.callId);
CallInfo ci = call->getInfo();
std::cout << "*** Incoming Call: " << ci.remoteUri << " ["
<< ci.stateText << "]" << std::endl;
emit pjt->resultReady2("ringing");
calls.push_back(call);
}
};
void MyCall::onCallState(OnCallStateParam &prm)
{
PJ_UNUSED_ARG(prm);
CallInfo ci = getInfo();
std::cout << "*** Call: " << ci.remoteUri << " [" << ci.stateText << "]" << std::endl;
pjt->info+="*** Call: ";
pjt->info+=QString::fromStdString(ci.remoteUri);
pjt->info+=" [";
pjt->info+=QString::fromStdString(ci.stateText);
pjt->info+="]\n";
pjt->infoChanged=true;
if (ci.state == PJSIP_INV_STATE_DISCONNECTED)
{
//pjt->remove_call=true;
myAcc->removeCall(this);
/* Delete the call */
delete this;
}
}
void MyCall::onCallMediaState(OnCallMediaStateParam &prm)
{
//PJ_UNUSED_ARG(prm);
CallInfo ci = getInfo();
AudioMedia aud_med;
try {
// Get the first audio media
aud_med = getAudioMedia(-1);
} catch(...) {
std::cout << "Failed to get audio media" << std::endl;
return;
}
AudioMedia& play_dev_med = Endpoint::instance().audDevManager().getPlaybackDevMedia();
AudioMedia& cap_dev_med = Endpoint::instance().audDevManager().getCaptureDevMedia();
pjt->info+="*** Connecting audio streams *** \n";
pjt->infoChanged=true;
// This will connect the sound device/mic to the call audio media
cap_dev_med.startTransmit(aud_med);
// And this will connect the call audio media to the sound device/speaker
aud_med.startTransmit(play_dev_med);
}
void MyCall::onCallTransferRequest(OnCallTransferRequestParam &prm)
{
/* Create new Call for call transfer */
prm.newCall = new MyCall(*myAcc);
}
void MyCall::onCallReplaced(OnCallReplacedParam &prm)
{
/* Create new Call for call replace */
prm.newCall = new MyCall(*myAcc, prm.newCallId);
}
MyAccount *acc(new MyAccount);
void make_call(QString num)
{
if(pjt->remove_call)
{
acc->removeCall(call);
/* Delete the call */
delete call;
pjt->remove_call=true;
}
std::cout << "here 1" << std::endl;
// Make outgoing call
call = new MyCall(*acc);
std::cout << "here 2" << std::endl;
acc->calls.push_back(call);
std::cout << "here 3" << std::endl;
CallOpParam prm(true);
std::cout << "here 4" << std::endl;
prm.opt.audioCount = 1;
prm.opt.videoCount = 0;
std::cout << "here 5" << std::endl;
call->makeCall(num.toStdString(), prm);
std::cout << "here 6" << std::endl;
}
static void mainProg1(Endpoint &ep)
{
// Init library
EpConfig ep_cfg;
ep_cfg.logConfig.level = 4;
ep_cfg.medConfig.threadCnt = 2;
ep.libInit( ep_cfg );
// Transport
TransportConfig tcfg;
tcfg.port = 5080;
ep.transportCreate(PJSIP_TRANSPORT_UDP, tcfg);
// Start library
ep.libStart();
std::cout << "*** PJSUA2 STARTED ***" << std::endl;
pjt->info="*** PJSUA2 STARTED ***\n";
emit pjt->resultReady(pjt->info);
// Add account
AccountConfig acc_cfg;
acc_cfg.idUri = "sip:2033@192.168.0.44";
acc_cfg.regConfig.registrarUri = "sip:192.168.0.44";
acc_cfg.sipConfig.authCreds.push_back( AuthCredInfo("digest", "*", "2033", 0, "PAss1234") );
try {
acc->create(acc_cfg);
} catch (...) {
std::cout << "Adding account failed" << std::endl;
}
//pj_thread_sleep(2000);
//make_call();
while(1)
{
if(pjt->state=="call")
{
pjt->state="";
std::cout << "############################# CALL ############################" << std::endl;
make_call(pjt->number);
std::cout << "###############################################################" << std::endl;
}
else if(pjt->state=="answer")
{
pjt->state="";
CallOpParam prm;
prm.statusCode = (pjsip_status_code)200;
call->answer(prm);
}
else if(pjt->state=="hangup")
{
pjt->state="";
CallOpParam prm;
prm.statusCode = (pjsip_status_code)486;
call->hangup(prm);
//ep.hangupAllCalls();
}
else if(pjt->infoChanged)
{
pjt->infoChanged=false;
emit pjt->resultReady(pjt->info);
}
else if(pjt->remove_call)
{
pjt->info+="Removing call...\n";
pjt->infoChanged=true;
acc->removeCall(call);
/* Delete the call */
delete call;
pjt->remove_call=false;
}
//ep.libHandleEvents(60);
}
// Hangup all calls
// pj_thread_sleep(4000);
// ep.hangupAllCalls();
// pj_thread_sleep(4000);
//
// Destroy library
std::cout << "*** PJSUA2 SHUTTING DOWN ***" << std::endl;
delete acc; /* Will delete all calls too */
}
int pjsua2_main()
{
int ret = 0;
Endpoint ep;
try {
ep.libCreate();
mainProg1(ep);
ret = PJ_SUCCESS;
} catch (Error & err) {
std::cout << "Exception: " << err.info() << std::endl;
ret = 1;
}
try {
ep.libDestroy();
} catch(Error &err) {
std::cout << "Exception: " << err.info() << std::endl;
ret = 1;
}
if (ret == PJ_SUCCESS) {
std::cout << "Success" << std::endl;
} else {
std::cout << "Error Found" << std::endl;
}
return ret;
}
这些是我的头文件:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
public slots:
void handleResults(const QString &s);
void handleResults2(const QString &ss);
private slots:
void on_callButton_clicked();
void on_callButton2_clicked();
void on_hangButton_clicked();
void on_answerButton_clicked();
};
#endif // MAINWINDOW_H
pjsuathread.h
#ifndef PJSUATHREAD_H
#define PJSUATHREAD_H
#include <QThread>
class PjsuaThread : public QThread
{
Q_OBJECT
public:
explicit PjsuaThread(QObject *parent = nullptr);
void run() override;
QString state;
QString info;
QString number;
bool infoChanged=false;
bool ringing=false;
bool remove_call=false;
signals:
void resultReady(const QString &s);
void resultReady2(const QString &ss);
};
#endif // PJSUATHREAD_H
和
pjsua2_main.h
#ifndef PJSUA2_MAIN_H
#define PJSUA2_MAIN_H
#include "pjsuathread.h"
int pjsua2_main();
extern PjsuaThread *pjt;
#endif // PJSUA2_MAIN_H
我解决了这个问题, 它是 pjproject 的版本。 现在我尝试使用 v2.10,一切正常。
v2.12 和 v2.11 不起作用,因为它们在我编译演示应用程序时给我未定义的引用。