2016-01-26 2 views
1

У меня проблема с приложением voip. Я использую PJSIP 2.4.5 (это последняя версия), и у меня проблема, когда мое приложение идет в фоновом режиме. Все в порядке на 30-40 секунд, тогда я не могу принимать входящие звонки, пока приложение не вернется на передний план. Я много искал, но я не нашел решения для своей проблемы.iOS: PJSIP background no входящие вызовы через 30-40 секунд

Это мой код, где я инициализирует PJSIP

static pjsua_acc_id acc_id; 
static pjsua_call_id incoming_call_id; 
static pjsua_call_id current_call_id; 
int imcalling=1; //this variable tell the program if I'm currently calling 

const size_t MAX_SIP_ID_LENGTH = 50; 
const size_t MAX_SIP_REG_URI_LENGTH = 50; 

static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata); 
static void on_call_state(pjsua_call_id call_id, pjsip_event *e); 
static void on_call_media_state(pjsua_call_id call_id); 
static void error_exit(const char *title, pj_status_t status); 

//pointers for the callbacks to objective-c 
void (*callee_response)(); 
void (*callee_hangup)(int); 
void (*call_incoming)(char*); 
void (*call_incoming_canceled)(char*); 
void (*call_get_statistics)(char*); 

int startPjsip(const char *sipUser, const char *sipPassword, const char* sipDomain, const char* realm, unsigned int reg_timeout, int transport_protocol, void(*incoming_call)(char*), void(*incoming_call_cancel)(char*), void(*get_call_statistics)(char*)) 
{ 
pj_status_t status; 

pjsip_cfg_t *mysipcfg = pjsip_cfg(); 
mysipcfg->tcp.keep_alive_interval = 20; 

// Create pjsua first 
status = pjsua_create(); 
if (status != PJ_SUCCESS) error_exit("Error in pjsua_create()", status); 

// Init pjsua 
{ 
    // Init the config structure 
    pjsua_config cfg; 
    pjsua_config_default (&cfg); 

    cfg.cb.on_incoming_call = &on_incoming_call; 
    cfg.cb.on_call_media_state = &on_call_media_state; 
    cfg.cb.on_call_state = &on_call_state; 

    // Init the logging config structure 
    pjsua_logging_config log_cfg; 
    pjsua_logging_config_default(&log_cfg); 
    log_cfg.console_level = 4; 

    // Init the pjsua 
    status = pjsua_init(&cfg, &log_cfg, NULL); 
    if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status); 
} 

// Add UDP transport. 
{ 
    // Init transport config structure 
    pjsua_transport_config cfg; 
    pjsua_transport_config_default(&cfg); 
    cfg.port = 5060; 

    // Add UDP transport. 
    status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, NULL); 
    if (status != PJ_SUCCESS) error_exit("Error creating transport", status); 
} 

// Add TCP transport. 
{ 
    // Init transport config structure 
    pjsua_transport_config cfg; 
    pjsua_transport_config_default(&cfg); 

    cfg.port = 5060; 

    // Add TCP transport. 
    status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &cfg, NULL); 
    if (status != PJ_SUCCESS) error_exit("Error creating transport", status); 
} 

// Initialization is done, now start pjsua 
status = pjsua_start(); 
if (status != PJ_SUCCESS) error_exit("Error starting pjsua", status); 

call_incoming=incoming_call; //pointer to the function that will tell to the app that a call is incoming 
call_incoming_canceled=incoming_call_cancel; //pointer to the function that will tell to the app that a call is canceled 
call_get_statistics=get_call_statistics; //pointer to the function that send the call statistics to the app 

// Register the account on sip server 
{ 
    pjsua_acc_config cfg; 

    pjsua_acc_config_default(&cfg); 

    char sipId[MAX_SIP_ID_LENGTH]; 
    sprintf(sipId, "sip:%[email protected]%s", sipUser, sipDomain); 
    cfg.id = pj_str(sipId); 

    char regUri[MAX_SIP_REG_URI_LENGTH]; 
    if(transport_protocol==1) sprintf(regUri, "sip:%s;transport=tcp", sipDomain); 
    else sprintf(regUri, "sip:%s", sipDomain); 
    cfg.reg_uri = pj_str(regUri); 

    cfg.reg_timeout = reg_timeout; 
    //cfg.ka_interval = 30; 

    cfg.cred_count = 1; 
    cfg.cred_info[0].realm = pj_str((char*)realm); 
    cfg.cred_info[0].scheme = pj_str("digest"); 
    cfg.cred_info[0].username = pj_str((char*)sipUser); 
    cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; 
    cfg.cred_info[0].data = pj_str((char*)sipPassword); 
    cfg.reg_retry_interval = 30; 

    //pj_log_set_level(6); 

    status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id); 
    if (status != PJ_SUCCESS) error_exit("Error adding account", status); 
} 

return 0; 

}

Таковы первые строки, напечатанные pjsip после активации

15:51:51.442 os_core_unix.c !pjlib 2.4.5 for POSIX initialized 
15:51:51.444 sip_endpoint.c .Creating endpoint instance... 
15:51:51.444   pjlib .select() I/O Queue created (0x16295940) 
15:51:51.444 sip_endpoint.c .Module "mod-msg-print" registered 
15:51:51.445 sip_transport. .Transport manager created. 
15:51:51.445 pjsua_core.c .PJSUA state changed: NULL --> CREATED 
15:51:51.447 sip_endpoint.c .Module "mod-pjsua-log" registered 
15:51:51.447 sip_endpoint.c .Module "mod-tsx-layer" registered 
15:51:51.447 sip_endpoint.c .Module "mod-stateful-util" registered 
15:51:51.447 sip_endpoint.c .Module "mod-ua" registered 
15:51:51.448 sip_endpoint.c .Module "mod-100rel" registered 
15:51:51.448 sip_endpoint.c .Module "mod-pjsua" registered 
15:51:51.448 sip_endpoint.c .Module "mod-invite" registered 
15:51:51.490 coreaudio_dev. .. dev_id 0: iPhone IO device (in=1, out=1) 8000Hz 
15:51:51.508 coreaudio_dev. ..core audio initialized 
15:51:51.509   pjlib ..select() I/O Queue created (0x16a63e14) 
15:51:51.547 sip_endpoint.c .Module "mod-evsub" registered 
15:51:51.547 sip_endpoint.c .Module "mod-presence" registered 
15:51:51.547 sip_endpoint.c .Module "mod-mwi" registered 
15:51:51.548 sip_endpoint.c .Module "mod-refer" registered 
15:51:51.548 sip_endpoint.c .Module "mod-pjsua-pres" registered 
15:51:51.548 sip_endpoint.c .Module "mod-pjsua-im" registered 
15:51:51.548 sip_endpoint.c .Module "mod-pjsua-options" registered 
15:51:51.549 pjsua_core.c .1 SIP worker threads created 
15:51:51.549 pjsua_core.c .pjsua version 2.4.5 for iPhone OS-9.2/arm-iPhone4,1/iOS-SDK-9.2 initialized 
15:51:51.549 pjsua_core.c .PJSUA state changed: CREATED --> INIT 
15:51:51.554 pjsua_core.c SIP UDP socket reachable at 192.168.100.174:5060 
15:51:51.556 udp0x16ab8400 SIP UDP transport started, published address is 192.168.100.174:5060 
15:51:51.559  tcptp:5060 SIP TCP listener ready for incoming connections at 192.168.100.174:5060 
15:51:51.559 pjsua_core.c PJSUA state changed: INIT --> STARTING 
15:51:51.559 sip_endpoint.c .Module "mod-unsolicited-mwi" registered 
15:51:51.559 pjsua_core.c .PJSUA state changed: STARTING --> RUNNING 
15:51:51.560 pjsua_acc.c Adding account: id=sip:[email protected] 
15:51:51.561 pjsua_acc.c .Account sip:[email protected] added with id 0 
15:51:51.561 pjsua_acc.c .Acc 0: setting registration.. 
15:51:51.563 tcpc0x1629d414 ..TCP client transport created 
15:51:51.564 tcpc0x1629d414 ..TCP transport 192.168.100.174:49474 is connecting to 37.187.161.173:5060... 
15:51:51.564 pjsua_acc.c ..Contact for acc 0 updated for SIP outbound: <sip:[email protected]:49474;transport=TCP;ob>;reg-id=1;+sip.instance="<urn:uuid:00000000-0000-0000-0000-0000d3a3575f>" 
15:51:51.566 pjsua_core.c ...TX 629 bytes Request msg REGISTER/cseq=17104 (tdta0x16abce00) to TCP 37.187.161.173:5060: 
REGISTER sip:37.187.161.173;transport=tcp SIP/2.0 

Я уверен, что я» m используя TCP для сокета, и я только что попытался удалить сокет udp, но ничего не изменилось. Поиск вокруг я увидел, что у кого-то есть такая же проблема, но через несколько минут, когда моя проблема возникает через полминуты или еще немного.

Я пытался даже установить интервал проверки активности pjsip, как вы можете видеть из этих линий:

pjsip_cfg_t *mysipcfg = pjsip_cfg(); 
mysipcfg->tcp.keep_alive_interval = 20; 

Я поставил его на 20 секунд, но ничего не изменилось. Звуковые и звуковые возможности добавляются в фоновый режим.

Я видел через сетевой монитор, что есть активное соединение с сервером voip, когда приложение находится на переднем плане. Когда приложение переходит в фоновое, это соединение исчезает через 3-4 секунды. Во всяком случае, я все еще могу получать входящие звонки в течение 30-40 секунд.

Любая идея о том, что я делаю неправильно?

+0

У меня возникла проблема, когда приложение находится в фоновом режиме. Проблема в том, что приложение может получить метод обратного вызова on_pager в iPhone5 с iOS8, но в iPhone6 ​​и 6Plus, где os-версия - это обратные вызовы iOS9, не запускаются. Любая идея об этом виде isse –

ответ

1

Просто нашел решение сам. Проблема была в reg_timeout конфигурации pjsua. Я использовал значение, переданное с сервера (60 секунд). Это значение было правильным, когда приложение было на переднем плане. Когда мое приложение было на заднем плане, вместо регистрации, истекающей через 60 секунд, и pjsip не смог ее продлить, потому что приложение iOS имеет минимальное время ожидания 600 секунд, чтобы проснуться с фона.

Решение заключалось в изменении тайм-аута reg, когда приложение переключилось на фон.

Вам нужна функция, как это:

void change timeout() { 
    pjsua_acc_config = cfg; 
    pjsua_acc_get_config(acc_id, pool, cfg); 
    cgf.reg_timeout = 600; 
    pjsua_acc_modify_config(acc_id, cfg) 
} 

Просто вы называете эту функцию, когда приложение переходит в фоновом режиме и изменить reg_timeout на 600. Тогда вы регистрируетесь снова. Когда приложение возвращается на передний план, вы делаете то же самое с первоначальным таймаутом.

Примечание что это должно было быть изменено с помощью Xcode 8 и iOS 10, обеспечивающих включение и отключение режима VOIP VOIP. По состоянию на январь 2016 года, если приложение отключено, вам необходимо запросить нажатие VOIP с вашего сервера.

+0

@Alex Zavatone: Где я пишу эту функцию? –

+1

Это изменилось с отключенным в фоновом режиме VOIP Apple. Теперь вам нужно выполнить VOIP, если приложение находится в автономном режиме и в фоновом режиме. Но сначала обязательно отправьте уведомление, чтобы вызвать этот метод, когда приложение переходит в фоновый режим. Этот метод должен быть в коде C, который имеет доступ к pjsip cfg. Я обновил ответ. –

+0

Да, с Xcode 8 Мне придется изменить эту часть. Спасибо. –

0

Для VOIP использовать это фоновый функции в AppDelegate.m

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    [self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES]; 

    [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler: ^{ 
     [self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES]; 

    }]; 

} 

static pj_thread_desc a_thread_desc; 
static pj_thread_t  *a_thread; 

- (void)keepAlive { 
    int i; 

    NSLog(@"Keep alive starts"); 
    if (!pj_thread_is_registered()) 
    { 
    pj_thread_register("ipjsua", a_thread_desc, &a_thread); 
    } 

/* Since iOS requires that the minimum keep alive interval is 600s, 
* application needs to make sure that the account's registration 
* timeout is long enough. 
*/ 
for (i = 0; i < (int)pjsua_acc_get_count(); ++i) { 
    if (pjsua_acc_is_valid(i)) { 
     pjsua_acc_set_registration(i, PJ_TRUE); 
    } 
} 


} 

он должен работать ..

+0

Спасибо за повтор, но у меня уже есть это в моем appdelegate. Однако проблема была другая: –

1

В целом PJSIP будет соединяться только через транспорт UDP.Если вам также нужны входящие вызовы в фоновом режиме, вам необходимо только подключиться только к TCP-транспорту, транспорт TCP поддерживает только передачу данных в реальном времени. Он следует за механизмом подтверждения запроса, поэтому, если приложение находится в фоновом состоянии, вызов попадет в приложение и отобразит локальное уведомление или другое, что когда-либо было реализовано для фона. В UDP он не проверяет, доставлен ли пакет или нет, в TCP он проверяет. Таким образом, чтобы получить входящий вызов в фоновом режиме, принудительно полностью настройте соединение только с TCP, не активируйте UDP.

0

Когда ваше приложение было в фоновом режиме, регистрация закончилась через 60 секунд, и pjsip не смог продлить его, потому что приложение iOS имеет минимальное время ожидания 600 секунд, чтобы проснуться от фона.

Смежные вопросы