VoIPGRID / VialerSIPLib

An Objective-c wrapper for PJSIP
GNU General Public License v3.0
133 stars 69 forks source link

Call destroyPJSUAInstance main-thread hangs. #232

Closed Meonardo closed 3 years ago

Meonardo commented 3 years ago

Version

Latest version(3.7.3).

File / Feature

File: VSLEndPoint.m Method: destroyPJSUAInstance pjsua_destroy();

Expected behavior

Destroy pjsua successfully.

Actual behavior

Call pjsua_destroy block the main-thread

Other info

The steps I was doing:

  1. hang up the call, - (BOOL)hangup:(NSError **)error
  2. unregister account, - (BOOL)unregisterAccount:(NSError * _Nullable __autoreleasing *)error
  3. remove account from endpoint, - (void)removeAccount:(VSLAccount *)account
  4. remove endpoint, - (void)removeEndpoint
  5. app hangs in - (void)destroyPJSUAInstance method pj_status_t status = pjsua_destroy();.
Meonardo commented 3 years ago

I finally figured out this problem by call pjsua_destroy in another thread(not the main thread), it worked but not recommend. As I found the documents on pjsip official website:

PJLIB API should be called from a registered thread, otherwise it will raise assertion such as "Calling pjlib from unknown/external thread...". With GCD, we cannot really be sure of which thread executing the PJLIB function. Registering that thread to PJLIB seems to be a simple and easy solution, however it potentially introduces a random crash which is harder to debug. Here are few possible crash scenarios:

PJLIB's pj_thread_desc should remain valid until the registered thread stopped, otherwise crash of invalid pointer access may occur, e.g: in pj_thread_check_stack().
Some compatibility problems between GCD and PJLIB, see #1837 for more info.
If you want to avoid any possibility of blocking operation by PJLIB (or any higher API layer such as PJMEDIA, PJNATH, PJSUA that usually calls PJLIB), instead of dispatching the task using GCD, the safest way is to create and manage your own thread pool and register that thread pool to PJLIB. Or alternatively, simply use PJSUA timer mechanism (with zero delay), see pjsua_schedule_timer()/pjsua_schedule_timer2() docs for more info.