New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Asynchronous conference bridge operation #3928
base: master
Are you sure you want to change the base?
Conversation
Since issue 2 is already handled, I assume it's no longer a problem (i.e. no longer causes backward compatibility)? Which only leaves issue 1. I understand it will be quite a lot to change all existing pjmedia_port(s) to have its own pool, but since it's necessary for this feature, I vote to continue. And if 1&2 are already resolved, the change in pjsua_app.c is no longer necessary, correct? (i.e. app will not need to change anything). |
The backward compatibility issues cannot be completely avoided, e.g:
Yes for |
Regarding issue 3, I don't think app is allowed to call The important thing here seems to be that |
Here is a sample scenario. App using PJSUA creates its own pool factory (instead of using PJSUA's) for some reason, and it uses the pool/factory to create a PJMEDIA port. It has to destroy the pool factory before shutting down PJSUA. Re: lib (PJSUA?) restart,
Yes, |
I see.
Ah, right. It's called upon |
In #3183, video conference bridge adopts asynchronous ports operations to handle non-uniform lock ordering issues. This PR integrates the same mechanism for audio conference bridge.
Beside avoiding deadlock, this change may improve performance a little bit as audio data processing in the conference bridge will be performed without holding a mutex.
There are some pending tasks (e.g: may also need to integrate this into audio switchboard, update PJMEDIA ports to have their own pool (see issues below)), but perhaps we need to discuss & decide whether the work should be continued.
Potential backward compatibility issues (major):
Pool release immediately after port removal, consider this code:
Note that the PJMEDIA tonegen port does not have its own pool (it allocates its own instances and all internal states using the supplied memory pool), so releasing the pool immediately after removing the port from conference bridge may cause crash as the port removal is now asynchronous and it may be still being accessed by the conference bridge.
Unfortunately, the real removal operation will not invoke any callback, so application cannot be so sure the safe time for releasing the pool. FYI the actual removal is done by the conference bridge clock which usually is a sound device, so if the clock is running, adding
pj_thread_sleep(100)
before relasing pool may avoid the crash (note that clock interval is usually 20ms, considering possible audio device burst, 100ms delay is generally sufficient).The proper solution is perhaps modifying the PJMEDIA tonegen to have its own pool.
PJMEDIA Stream pattern.
PJMEDIA Stream exports a PJMEDIA port interface which can be queried using
pjmedia_stream_get_port()
. Unfortunately the port does not implementspjmedia_port_destroy()
, it is destroyed usingpjmedia_stream_destroy()
instead, which will release the memory pool. Similar to above issue, ifpjmedia_stream_destroy()
is invoked immediately afterpjmedia_conf_remove_port()
, it may cause crash. Ifpjmedia_port_destroy()
is implemented (FYI this PR actually implements it for PJMEDIA Stream), it should not crash as the conference bridge will install group lock to the PJMEDIA port andpjmedia_port_destroy()
implementation will only be called after group lock's reference counter reaches zero.Caching pool destroy.
When all PJMEDIA ports have their own pools, there is still possibility that application uses its pool factory for creating the ports and destroy the pool factory (e.g: invoking
pj_caching_pool_destroy()
) prematurely before the actual port removal is done. For example, in application shutdown, the conference bridge clock has been stopped so actual port removal can only be done later bypjmedia_conf_destroy()/pjsua_destroy()
, but in between, application may destroy its pool factory which may cause crash.A possible solution is to delay the pool factory destroy to PJLIB deinitialization via
pj_atexit()
.