Pjsua and readyReadStandardOutput BIG problem
-
Hi, I am trying to call Pjsua (voip client) from my gui application.
Pjsua via command line works perfectly and smoothly.
But when launched as an external process sometimes I cannot read ALL its standrad output, but only the first chuncks.Sometimes it works, but it's one in a million....
What am I doing wrong? (hope this thread will be useful to those who want to itegrate pjsua in their projects without using API's)
TIA
@
QProcess *processo;
QByteArray result;MainWindow::~MainWindow()
{
delete ui;
}
*/Frm_column::Frm_column(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Frm_column)
{
ui->setupUi(this);...
processo = new QProcess();
processo->closeWriteChannel();
processo->setReadChannelMode(QProcess::MergedChannels);
...QObject::connect( processo, SIGNAL(readyRead()),
this, SLOT(processStdOut()));
...
}void Frm_column::on_pushButton_clicked()
{if (processo->isOpen())
processo->close();QString program = "/home/.../bin/pjsua";
QStringList arguments;
arguments << "sip:100@..." << "--id=sip:101@..." << "--registrar=sip:..." << "--realm=*" << "--username=..." << "--password=...";processo->setWorkingDirectory("/home/...bin/");
processo->start(program, arguments);
}
int Frm_column::getCallStatus(QStringList sl)
{
foreach (QString line, sl) {// this one first cause calling state appears here as well
if (line.contains("state changed to CONFIRMED", Qt::CaseInsensitive))
return 2; // answered there!!
else if (line.contains("state changed to CALLING", Qt::CaseInsensitive))
return 1; // ringing there
//else if (line.contains(QRegExp("Call .* is DISCONNECTED/i")))
else if (line.contains(" is DISCONNECTED",Qt::CaseInsensitive))
return 3; // iI hanged up
else if (line.contains("state changed to EARLY", Qt::CaseInsensitive))
return 4; // messo giu' per troppi squilli
}
return 0;
}void Frm_column::processStdOut()
{result=processo->readAll();
QStringList lines = QString(result).split("\n");
int statusCall = getCallStatus(lines);
foreach (QString line, lines)
ui->txtVoipStdout->append(line);switch (statusCall)
{
case 1:
ui->txtVoipStderr->append("Calling");
break;
case 2:
ui->txtVoipStderr->append("Talking");
break;
case 3:
ui->txtVoipStderr->append("I hanged up");
voipKill();
break;
case 4:
ui->txtVoipStderr->append("You hanged up");
voipKill();
break;}
}
void Frm_column::on_pushButton_2_clicked()
{
voipKill();
}// soft kill, hard kill is performed at timeout
void Frm_column::voipKill()
{
if (processo->isOpen())
{
processo->write("\n\n\nq\n");
processo->closeWriteChannel();
voipKilling = true;
voipKilledTime.restart();
}
}@
-
Your function processStdOut might also get partial lines. readyRead only implies that data was written by the process. It does not know, whether there is more data to write or not. It also does not know, how much data is currently cachecd by the process...
-
so how do I get to know that there's simething in the buffer?
I need to react to any stdout message asap... -
Seems to be an issue of stdout buffering. You will have to make sure that the program you call flushes the output buffer. Default is usually 4096 bytes (4k). If you cannot trick your program into flushing the buffer, there's no other option than waiting until the OS flushes it.
-
Ok, luckily I can put my hands on pjsip sources and
unbuffered
setvbuf(stdout, NULL, _IONBF, 0)
line buffered
setlinebuf(stdout)
for anyhone with the same problem another solution (if you don't have program sources) -which seems to do the trick- is here:
http://coderrr.wordpress.com/2008/12/20/automatically-flushing-redirected-or-piped-stdout/