voiceip / tinyphone

Minimalist Windows / OSx / Linux SIP Softphone with API Control
GNU General Public License v3.0
114 stars 36 forks source link

Low volume / no sound between participants in conference #80

Open pdesaulniers-vertisoft opened 7 months ago

pdesaulniers-vertisoft commented 7 months ago

Hello,

We are experiencing an issue with the 'conference' feature.

During a conference, the host can hear the participants at a reasonable volume, and the participants can also hear the host. However, the participants can barely hear each other. It seems like the audio between participants is very quiet.

Here is an example scenario:

Do you know why this issue might occur? Or, do you have any suggestions for debugging this problem?

Here is the content of config.json, in case it might be related to the issue:

{
    "audioCodecs": ["PCMA/8000/1", "PCMU/8000/1", "G729/8000/1"],
    "dropCallsOnFail": false,
    "firstRetryIntervalSec": 15,
    "maxAccounts": 3,
    "maxCalls": 4,
    "pjThreadCount" : 2,
    "pjMediaThreadCount" : 4,
    "pjLogLevel": 3,
    "retryIntervalSec": 30,
    "timeoutSec": 600,
    "refreshIntervalSec" : 120,
    "transport": 1,
    "uaPrefix": "TinyPhone Pjsua2 v",
    "prefferedAudioDevices" : [ "sound", "usb" , "headphone", "audio" , "microphone" , "speakers" ],
    "useDefaultAudioDevice" : true,
    "securityCode" : "D9C853F4897CF64307DB652246827FAC83111303F3E207F8FD9F5E5DC89A9EF9",
    "autoUnHold" : false,
    "testAudioDevice" : true,
    "unregisterOnDeviceError" : true,
    "deviceErrorAlert" : true,
    "disableVAD" : true,
    "clockRate" : 8000,
    "enableNoiseCancel" : false,
    "ecTailLen" : 200,
    "enableWSEvents" : true,
    "enableMetrics" : false,
    "metricsProto" : "UDP",
    "metricsServerHosts" : ["10.47.192.13"],
    "metricsServerPort" : 8125,
    "autoDeviceRefresh" :  true,
    "autoAnswer" : false,
    "persistAccounts" : true,
    "enableSTUN" : false,
    "enableICE" : false,
    "stunServers" : [ "stun.l.google.com:19302" ],
    "handleNOTIFY" : true,
    "autoAnswerDelay" : 1000
}
kingster commented 7 months ago

Hi @pdesaulniers-vertisoft

I personally don't use the conference flow in my deployments and this feature was a done based on community request #39 but I was never able to completely test this feature. One hypothesis that I have is this could be based on the way it is implemented. The current implementation is where the audio channels are linked with each other

aud_med.startTransmit(aud_med2);
aud_med2.startTransmit(aud_med);

An alternative could be using pjsua_conf_connect() documentation. This will require minor change but would you like to take a stab at this and see if this works?

kingster commented 7 months ago

An alternative could be using pjsua_conf_connect() documentation. This will require minor change but would you like to take a stab at this and see if this works?

My bad I double checked the documentation of pjusa2 and the aud_med.startTransmit(aud_med2) is the right way only https://docs.pjsip.org/en/latest/pjsua2/using/media_audio.html#conference-call

I will see if there is any way to replicate the issue, but not sure I would be able to because I have only 1 single device to test on.

pdesaulniers-vertisoft commented 7 months ago

Hello,

Yes, this feature is a bit difficult to test :)

We did some further testing yesterday, and this time, the participants could not hear each other at all. So, during our initial tests, perhaps the host's microphone was picking up the sound from his headset, and the participants were hearing each other through the host's microphone, hence why the volume between participants was very low...

I've looked at PJSIP's documentation, and it does seem like TinyPhone is implementing conference calls in the recommended manner.

I'm not very familiar with PJSIP... Could this issue occur because UnHoldCall is called after getAudioMedia in some cases? In PJSIP's documentation, there is no UnHoldCall, the call appears to be already active when getMedia and startTransmit are executed.

Or, perhaps there is more than one audio media per call, and getAudioMedia(-1) is picking up the wrong one?

pdesaulniers-vertisoft commented 7 months ago

Regarding this comment:

Could this issue occur because UnHoldCall is called after getAudioMedia?

My bad, this scenario doesn't appear to be possible, since the endpoint returns 'Bad Request' if the call is currently on hold.

We will do some further testing today and see if we can figure out the issue...

pdesaulniers-vertisoft commented 7 months ago

Actually, I investigated the issue in more detail, and it seems like the problem was on our end. We are using a slightly forked version of the softphone, and the issue was probably caused by some changes which were done internally by one of our developers.

In our case, UnHoldCall was being called after getAudioMedia. Once we swapped the order, the bi-directional audio between participants started working correctly.

Very sorry for wasting your time!

pdesaulniers-vertisoft commented 4 months ago

After further verification, it seems that we can still reproduce the issue, using TinyPhone::Join as implemented in https://github.com/voiceip/tinyphone/pull/81 ...

On second thought, we think it might be caused by some kind of race condition between SIPCall::UnHoldCall and one of the following method calls (either getAudioMedia or startTransmit). For testing purposes, we naively added a pause between UnHoldCall and getAudioMedia (using std::this_thread::sleep_for), and it appears to bypass the issue.

Based on the code, it looks like UnHoldCall sends a re-INVITE SIP message. Perhaps the audio media (or the audio transmission) is somehow 'invalidated' by the re-INVITE message? In other words:

We are not sure if this scenario is possible, but maybe it would explain the behavior that we noticed during our tests...

EDIT: According to PJSIP's logs, it does seem like re-INVITE leads to an SDP negotation a few milliseconds later, which causes PJSIP to destroy the media stream...

2023-12-18 09:40:39.465   pjsua_call.c  Sending re-INVITE on call 0
2023-12-18 09:40:39.465  pjsua_media.c  .Call 0: re-initializing media..
2023-12-18 09:40:39.465  pjsua_media.c  ..Media index 0 selected for audio call 0
2023-12-18 09:40:39.465   pjsua_core.c  ....TX 1227 bytes Request msg INVITE/cseq=26300 [...] to UDP <address>:<port>

[...]

2023-12-18 09:40:39.508   pjsua_core.c !.RX 487 bytes Response msg 100/INVITE/cseq=26300 [...] from UDP <address>:<port>

[...]

2023-12-18 09:40:39.557   pjsua_core.c !.RX 884 bytes Response msg 200/INVITE/cseq=26300 [...] from UDP <address>:<port>

[...]

2023-12-18 09:40:39.558    inv00D0E45C  ....SDP negotiation done: Success
2023-12-18 09:40:39.558  pjsua_media.c  .....Call 0: updating media..
2023-12-18 09:40:39.558  pjsua_media.c  .......Media stream call00:0 is destroyed