首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用PJSUA2打电话

用PJSUA2打电话
EN

Stack Overflow用户
提问于 2021-01-19 10:55:12
回答 1查看 800关注 0票数 1

我是PJSUA2新手,我正在尝试使用这个库打电话。我已经设法在远程sip服务器上授权了,但是调用更加困难。下面是代码:

代码语言:javascript
复制
#include <iostream>
#include <pjsua2.hpp>
#include <pjsua2/media.hpp>

using namespace std;
using namespace pj;

bool active = true;
//AudioMedia *aud_med;

class MyAccount : public Account
{
public:
    vector<Call *> calls;

MyAccount()
{}

~MyAccount()
{
    std::cout << "======= Account is being deleted: No of calls = " << calls.size() << std::endl;

    for (vector<Call *>::iterator it = calls.begin(); it != calls.end(); )
    {
        delete (*it);
        it = calls.erase(it);
    }
}

void removeCall(Call *call)
{
    for (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:" : "*** Unregister:")
              << " code=" << prm.code << std::endl;
}
};

class MyAudioPlayer : public AudioMediaPlayer
{
public:
    MyAudioPlayer() : AudioMediaPlayer()
{

}

~MyAudioPlayer()
{

}

void onEof2()
{
    cout << "======= End of file reached" << endl;
    //this->stopTransmit(*aud_med);
    active = false;
}
};

//MyAudioPlayer player;

class MyCall : public Call
{
private:
    MyAccount *myAcc;
    MyAudioPlayer *wav_player;
public:
    MyCall(Account &acc, int callId = PJSUA_INVALID_ID) : Call(acc, callId)
    {
    myAcc = (MyAccount *)&acc;
    wav_player = NULL;
}

~MyCall()
{
    if (wav_player)
    {
        delete wav_player;
        cout << "======= Player deleted!" << endl;
    }

}

void onCallState(OnCallStateParam &state_param)
{
    CallInfo info = getInfo();

    cout << "======= CallState is: " << info.stateText << " =======" << endl;

    if(info.state == PJSIP_INV_STATE_CONFIRMED)
    {

    }
    else if (info.state == PJSIP_INV_STATE_DISCONNECTED)
    {
        myAcc->removeCall(this);
        //wav_player->stopTransmit(*aud_med);
        active = false;
        //delete wav_player;
        //delete this;
    }
}

void onCallMediaState(OnCallMediaStateParam &media_param)
{
    cout << "======= OnCallMediaState is called! =======" << endl;

    CallInfo ci = getInfo();

    if (ci.state == PJSIP_INV_STATE_CONFIRMED)
    {
        AudioMedia aud_med;

        AudioMedia& play_dev_med = Endpoint::instance().audDevManager().getPlaybackDevMedia();

        /*
        for (unsigned i = 0; i < ci.media.size(); i++)
        {
            if (ci.media[i].type == PJMEDIA_TYPE_AUDIO && getMedia(i))
            {
                aud_med = (AudioMedia *)getMedia(i);
                //aud_med.startTransmit(play_dev_med);
                break;
            }
        }
        */

        try
        {
            // Get the first audio media
            aud_med = getAudioMedia(-1);
            std::cout << "======= Got audio media!" << std::endl;
        }
        catch(...)
        {
            std::cout << "======= Failed to get audio media" << std::endl;
            return;
        }


        if (!wav_player)
        {
            wav_player = new MyAudioPlayer();

            try
            {
                wav_player->createPlayer("input.wav", PJMEDIA_FILE_NO_LOOP);
                wav_player->adjustRxLevel(3.0);
                cout << "======= Created wav player" << endl;
            }
            catch (...)
            {
                cout << "======= Failed opening wav file" << endl;
                delete wav_player;
                wav_player = NULL;
            }
        }

        aud_med.startTransmit(play_dev_med);

        if (wav_player)
            wav_player->startTransmit(aud_med);
    }
}

virtual void onCallReplaced(OnCallReplacedParam &prm)
{
    prm.newCall = new MyCall(*myAcc, prm.newCallId);
}

virtual void onCallTransferRequest(OnCallTransferRequestParam &prm)
{
    prm.newCall = new MyCall(*myAcc);
}
};

int main()
{
Endpoint ep;

ep.libCreate();

// Initialize endpoint
EpConfig ep_cfg;
ep_cfg.logConfig.level = 6;
ep.libInit( ep_cfg );

// Create SIP transport. Error handling sample is shown
TransportConfig tcfg;
tcfg.port = 0;
try
{
    ep.transportCreate(PJSIP_TRANSPORT_UDP, tcfg);
}
catch (Error &err)
{
    cout << err.info() << endl;
    return 1;
}

// Start the library (worker threads etc)
ep.libStart();
cout << "*** PJSUA2 STARTED ***" << endl;

// Configure an AccountConfig
AccountConfig acfg;
acfg.idUri = "sip:[account1]@[server]";
acfg.regConfig.registrarUri = "sip:[server]";
AuthCredInfo cred("digest", "*", "[account1]", 0, "[password]");
acfg.sipConfig.authCreds.push_back( cred );

// Create the account
MyAccount *acc = new MyAccount;
try
{
    acc->create(acfg);
}
catch(Error &err)
{
    cout << "The error is: " << err.info() << endl;
    return 1;
}

pj_thread_sleep(1500);

string call_uri = "sip:[callee]@[server]";

cout << endl;
cout << "======= Destination uri: " << call_uri << endl;
cout << endl;

Call *call = new MyCall(*acc);
acc->calls.push_back(call);
CallOpParam prm(true);
prm.opt.audioCount = 1;
prm.opt.videoCount = 0;
call->makeCall(call_uri, prm);

pj_thread_sleep(4000);
cout << "======= Cycle ended" << endl;

ep.hangupAllCalls();
cout << "======= All calls hanged up" << endl;
// Here we don't have anything else to do...
pj_thread_sleep(4000);

// Delete the account. This will unregister from server
delete acc;

// This will implicitly shutdown the library
return 0;
}

在这里,我使用凭证创建MyAccount实例(这些都是正确的),并尝试调用。在那个调用被删除之后(因为被调用者没有被授权,所以我得到了PJSIP_INV_STATE_DISCONNECTED),但是帐户不能被删除。它写着“删除帐户0”,并且什么也不做(就像它停留在MyAccount析构函数中的某个无限循环上)。但是如果我不打一个电话(与makeCall的注释线),帐户就会被删除。关于这个问题,我已经没有选择了。请帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-28 13:10:13

我设法弄清楚了,所以如果有人有这个问题,我会留下答案的。原来电话挂错了(或者根本没挂,不知道)。为了解决这个问题,我更改了onCallState回调,应该如下所示:

代码语言:javascript
复制
void onCallState(OnCallStateParam &state_param)
{
    CallInfo info = getInfo();

    cout << "======= CallState is: " << info.stateText << " =======" << endl;

    if(info.state == PJSIP_INV_STATE_CONFIRMED)
    {
        // do stuff
    }
    else if (info.state == PJSIP_INV_STATE_DISCONNECTED)
    {
        // do stuff related to call disconnection
        myAcc->removeCall(this);
        delete this;
        return;
    }
}

只需在回调结束时删除调用实例(删除此),然后返回。这是正确的挂起调用的方式,因此与该调用相关的线程也被正确删除。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65790101

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档