Search code examples
androidc++11voiprtppjsip

Voice quality issue in Android VoIP app with PJSIP


We are developing a VoIP app using PJSIP. The internal core module is in C++11 and external UI is in Java. Following C++11 threads are created:

  1. Main thread
  2. Observer thread, which wakes up every 3 minutes and quickly goes to sleep
  3. SSL read + write thread (SSL read socket is connected through internet to server)
  4. A part time TCP thread which is active/inactive for RESTful API (creates socket on 9100)
  5. SIP thread which connects with PJSIP (creates socket on 5060)
  6. 2 RTP threads per call (creates socket pair, e.g. 40000, 40001)

The same C++11 module is also present in the iOS/MAC app where it works just fine. The Android app also works fine, but the voice quality is not always good.
[Note: We ruled out the built-in Android SIP stack because it doesn't support 3G.]

I suspected that C++11 (total 8) threads are the culprit and also posted a question:
c++11 multithreading issues with Android where some threads are not scheduled properly
But that seems a remote possibility to me, because during a voice call, only 4 threads are majorly active:
2 SSL + 2 RTP (Also, it works fine in iOS. MacOS).

Right now my suspicion is on PJSIP, because, if we make a call from:

  1. App to App then the voice quality is 70+% time good
  2. App to GSM then the voice quality is always good at App side, but always shaking at GSM side

Any help would be much appreciated and if it fixes the issue, a bounty would be rewarded. (I had already started a bounty around 12 January, but no reply/comment during then)


Solution

  • This issue is not probably due to PJSIP or multi threads in Android. Actually the TLS tunnel we use to connect the mobile and the server is on TCP which is a bad choice for sending RTP data.
    However, I don't have any idea how iOS and Mac manages to generate such a good sound quality.

    Having said these, below option really helped to reduce the voice quality issue:

    const int optionValue = 1;  // `int` is preferred
    (void) ::setsockopt(m_ID, IPPROTO_TCP, TCP_NODELAY, &optionValue, sizeof(optionValue));
    

    Read more about TCP_NODELAY flag in this article.