I am trying to make a call using PJSUA2, play a wav file to the callee, and callee should record this file to wav. I created two programs for that (caller and callee). And when caller starts playing wav file into AudioMedia object, console of callee program just spams out "alsa.c pb_thread_func: underrun!" and nothing can be heard or recorded.
Here is caller main.cpp:
#include <iostream>
#include <pjsua2.hpp>
#include <pjsua2/media.hpp>
using namespace std;
using namespace pj;
bool active = true;
class MyAccount : public Account
{
public:
vector<Call *> calls;
MyAccount()
{}
~MyAccount()
{
shutdown();
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
{
private:
AudioMedia audio;
public:
MyAudioPlayer(AudioMedia aud_med) : AudioMediaPlayer()
{
audio = aud_med;
}
~MyAudioPlayer()
{
}
virtual void onEof2();
};
void MyAudioPlayer::onEof2()
{
cout << "======= End of file reached" << endl;
this->stopTransmit(audio);
active = false;
return;
}
//MyAudioPlayer player;
class MyCall : public Call
{
private:
MyAccount *myAcc;
MyAudioPlayer *wav_player;
AudioMedia aud_med;
public:
MyCall(Account &acc, int callId = PJSUA_INVALID_ID) : Call(acc, callId)
{
wav_player = NULL;
myAcc = (MyAccount *)&acc;
}
~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);
active = false;
delete this;
return;
}
}
void onCallMediaState(OnCallMediaStateParam &media_param)
{
cout << "======= OnCallMediaState is called =======" << endl;
CallInfo ci = getInfo();
cout << "======= CallState is: " << ci.stateText << " =======" << endl;
//AudioMedia aud_med;
AudioMedia& play_dev_med = Endpoint::instance().audDevManager().getPlaybackDevMedia();
try
{
// Get the first audio media
aud_med = getAudioMedia(-1);
cout << "======= Got audio media" << endl;
}
catch(...)
{
cout << "======= Failed to get audio media" << 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;
}
}
cout << "======= Playing file" << endl;
if (wav_player)
{
wav_player->startTransmit(aud_med);
}
//aud_med.startTransmit(play_dev_med);
}
};
int main()
{
Endpoint ep;
ep.libCreate();
// Initialize endpoint
EpConfig ep_cfg;
ep_cfg.logConfig.level = 5;
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:[caller]@[server]";
acfg.regConfig.registrarUri = "sip:[server]";
AuthCredInfo cred("digest", "*", "[caller]", 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(6000);
ep.hangupAllCalls();
cout << "======= All calls hanged up" << endl;
// Here we don't have anything else to do...
pj_thread_sleep(1000);
// Delete the account. This will unregister from server
delete acc;
// This will implicitly shutdown the library
return 0;
}
And here in callee main.cpp:
#include <iostream>
#include <pjsua2.hpp>
#include <pjsua2/media.hpp>
using namespace std;
using namespace pj;
bool active = true;
class MyAccount : public Account
{
public:
vector<Call *> calls;
MyAccount()
{}
~MyAccount()
{
shutdown();
cout << "======= Account is being deleted: No of calls = " << calls.size() << 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();
cout << (ai.regIsActive? "*** Register:" : "*** Unregister:")
<< " code=" << prm.code << endl;
}
virtual void onIncomingCall(OnIncomingCallParam &call_prm);
};
class MyCall : public Call
{
private:
MyAccount *myAcc;
AudioMediaRecorder *wav_recorder;
AudioMedia aud_med;
public:
MyCall(Account &acc, int callId = PJSUA_INVALID_ID) : Call(acc, callId)
{
myAcc = (MyAccount *)&acc;
wav_recorder = NULL;
}
~MyCall()
{
if (wav_recorder)
{
try
{
aud_med.stopTransmit(*wav_recorder);
}
catch(Error& err)
{
cout << "Error: " << err.info() << endl;
}
delete wav_recorder;
cout << "======= Recorder deleted =======" << endl;
}
}
void onCallState(OnCallStateParam &state_param)
{
CallInfo info = getInfo();
cout << "======= OnCallState: callState is: " << info.stateText << " =======" << endl;
if(info.state == PJSIP_INV_STATE_CONFIRMED)
{
}
else if (info.state == PJSIP_INV_STATE_DISCONNECTED)
{
aud_med.stopTransmit(*wav_recorder);
myAcc->removeCall(this);
active = false;
delete this;
return;
}
}
void onCallMediaState(OnCallMediaStateParam &media_param)
{
CallInfo ci = getInfo();
cout << "======= OnCallMediaState: callState is: " << ci.stateText << " =======" << endl;
try
{
// Get the first audio media
aud_med = getAudioMedia(-1);
cout << "======= Got audio media =======" << endl;
}
catch(...)
{
cout << "======= Failed to get audio media =======" << endl;
return;
}
if (!wav_recorder)
{
wav_recorder = new AudioMediaRecorder();
try
{
wav_recorder->createRecorder("test.wav");
cout << "======= Created wav recorder =======" << endl;
}
catch (...)
{
cout << "======= Failed opening wav file =======" << endl;
delete wav_recorder;
wav_recorder = NULL;
}
}
AudioMedia& play_dev_med = Endpoint::instance().audDevManager().getPlaybackDevMedia();
aud_med.startTransmit(play_dev_med);
if (wav_recorder)
{
cout << "======= Recording file =======" << endl;
aud_med.startTransmit(*wav_recorder);
}
}
};
MyCall *incomingCall;
void MyAccount::onIncomingCall(OnIncomingCallParam &call_prm)
{
cout << "======= OnIncomingCall is called =======" << endl;
incomingCall = new MyCall(*this, call_prm.callId);
CallInfo ci = incomingCall->getInfo();
CallOpParam prm;
cout << "*** Incoming Call: " << ci.remoteUri << " ["
<< ci.stateText << "]" << endl;
calls.push_back(incomingCall);
prm.statusCode = (pjsip_status_code)200;
incomingCall->answer(prm);
}
int main()
{
Endpoint ep;
ep.libCreate();
// Initialize endpoint
EpConfig ep_cfg;
ep_cfg.logConfig.level = 8;
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)
{
std::cout << err.info() << std::endl;
return 1;
}
// Start the library (worker threads etc)
ep.libStart();
cout << "*** PJSUA2 STARTED ***" << endl;
// Configure an AccountConfig
AccountConfig acfg;
acfg.idUri = "sip:[callee]@[server]";
acfg.regConfig.registrarUri = "sip:[server]";
AuthCredInfo cred("digest", "*", "[callee]", 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;
}
// Here we don't have anything else to do...
while(active)
{
}
pj_thread_sleep(1000);
ep.hangupAllCalls();
// Delete the account. This will unregister from server
delete acc;
// This will implicitly shutdown the library
return 0;
}
Audio out works fine, so this is definitely AudioMedia issue (perhaps I’m connecting it in a wrong way). Does anyone has any ideas about what is wrong?
Source: Windows Questions C++