iOS Voip Socket не будет работать в фоновом режиме

Я получаю VOIP-сокет для фонового запуска в приложении для iOS.

Мое соединение работает нормально, но оно не проснется, когда мое приложение перейдет в фоновый режим. Если я снова открою приложение, оно ответит на любые сообщения, полученные во время сна.

Я настроил свой поток так:

CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
                                   (CFStringRef) @"test.iusealocaltestserver.com",
                                   5060,
                                   &myReadStream,
                                   &myWriteStream);
CFReadStreamSetProperty (    myReadStream,
                             kCFStreamNetworkServiceType,
                             kCFStreamNetworkServiceTypeVoIP
                             );

CFSocketNativeHandle native;
CFDataRef nativeProp = CFReadStreamCopyProperty(myReadStream, kCFStreamPropertySocketNativeHandle);

CFDataGetBytes(nativeProp, CFRangeMake(0, CFDataGetLength(nativeProp)), (UInt8 *)&native);
CFRelease(nativeProp);

CFSocketRef theSocket = CFSocketCreateWithNative(kCFAllocatorDefault, native, 0, NULL, NULL);

CFSocketGetContext(theSocket,&theContext);    


CFOptionFlags readStreamEvents = kCFStreamEventHasBytesAvailable | 
kCFStreamEventErrorOccurred     |
kCFStreamEventEndEncountered    |
kCFStreamEventOpenCompleted;

CFReadStreamSetClient(myReadStream,
                           readStreamEvents,
                           (CFReadStreamClientCallBack)&MyCFReadStreamCallback,
                      (CFStreamClientContext *)(&theContext));

CFReadStreamScheduleWithRunLoop(myReadStream, CFRunLoopGetCurrent(),
                                kCFRunLoopCommonModes);

Тогда мой обратный вызов настроен так:

static void MyCFReadStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *pInfo);

static void MyCFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSLog(@"Callback Happened");

   [pool release];
}

"Callback Happened" вызывается, когда я получаю данные, и приложение открыто, но это не так, если приложение свернуто. Однако, когда приложение возвращается, оно обрабатывает любые данные, полученные при минимизации.

Я добавил тэг voip в список info.plist. Мой CFReadStreamSetProperty возвращает true. Я работаю на устройстве, а не на симуляторе. Это все еще не работает, поэтому я не знаю, в чем может быть моя проблема. Я, наверное, просто сделал что-то глупое, но в интернете почти ничего не проверяется.

РЕДАКТИРОВАТЬ: я не могу проверить ни один из ответов, потому что я больше не работаю над этим проектом и не имею доступа к Mac / IOS SDK. Если кто-то с подобной проблемой нашел один из приведенных ниже ответов полезным, дайте мне знать, и я проголосую за лучший ответ.

5 ответов

Решение

Если вы хотите, чтобы ваше приложение VOIP работало в фоновом режиме, за исключением тех базовых настроек в файле plist, вам нужен сокет TCP, свойство которого установлено в VOIP, а система iOS позаботится об этом сокете, когда ваше приложение войдет в фоновый режим, каждая вещь была "спящей", за исключением этого сокета TCP. и если VOIP-сервер отправит некоторые данные, полагая, что TCP-сокет, ваше приложение будет активировано в течение 10 секунд. За это время вы можете опубликовать локальное уведомление.

Только Tcp-сокет может быть установлен как VOIP-сокет. Но насколько я знаю, в основном приложения VOIP основаны на сокете UDP. если вы не хотите отделять управляющий сокет от сокета данных. вам следует создать еще один сокет tcp, который предназначен для "пробуждения" вашего приложения, и из моего личного опыта очень трудно поддерживать синхронизацию этого "пробужденного" сигнала и реального управляющего сигнала SIP, приложение всегда пропускает запрос SIP-приглашения.

Таким образом, лучший способ - отделить одиночный элемент управления sip от сокета данных UDP, сделать его как сокет TCP, это лучшее решение, но никогда не используйте сокет TCP для передачи голосовых данных.

Другой грязный способ: держать приложение бодрствующим все время. Как я уже сказал, каждый TCP-сингл, полученный приложением, думал, что tcp-сокет 'VOIP' будет держать приложение в активном состоянии в течение 10 секунд, поэтому по окончании этого периода (через 9 секунд) вы можете отправить ответ на сервер, чтобы запросить другой сигнал, когда поступит следующий сигнал, приложение снова проснется, через 9 секунд снова отправит ответ. продолжайте делать это, ваше приложение проснется навсегда.

Я застрял с точно таким же сценарием.
Моя проблема заключалась в том, что я настроил более одного сокета в качестве сокета Voip.

Вы можете увидеть в документации Apple о VoIP, что они говорят:
"Настройте один из сокетов приложения для использования VoIP"

Я предполагаю, что они пробуждают ваше приложение только по одному сокету.

все другие упомянутые вещи все еще правильны:

  • kCFStreamNetworkServiceTypeVoIP
  • 'info.plist' UIBackgroundModes: voip, audio
  • 'info.plist' UIRequiresPersistentWifi ключ
  • НЕ будет работать над симулятором

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

  1. Wi-Fi -> 3 г
  2. 3g -> Wi-Fi

Через некоторое время, скажем снова, я пытаюсь переключить сеть вручную. ничто не радует, кажется, мое приложение не обнаруживает сетевых изменений. Я прочитал ниже Apple Doc. я уверен, что неправильно (или) неправильно понял шаги 3 и 6.

Существует несколько требований для реализации приложения VoIP:

1. Добавьте ключ UIBackgroundModes в файл Info.plist вашего приложения. Установите значение этого ключа для массива, который включает строку voip.

  1. Настройте один из сокетов приложения для использования VoIP.

  2. Прежде чем перейти к фону, вызовите метод setKeepAliveTimeout:handler: для установки обработчика, который будет выполняться периодически. Ваше приложение может использовать этот обработчик для поддержания своего сервисного соединения.

  3. Сконфигурируйте ваш аудио сеанс для обработки переходов в активное использование.

5. Чтобы обеспечить лучшее взаимодействие с пользователем на iPhone, используйте платформу Core Telephony для настройки вашего поведения в отношении телефонных звонков на сотовой основе; см. Базовую Ссылку Платформы телефонии.

  1. Чтобы обеспечить хорошую производительность для вашего VoIP-приложения, используйте инфраструктуру конфигурации системы, чтобы обнаружить изменения в сети и позволить вашему приложению как можно дольше спать.

Вам может понадобиться установить <key>UIBackgroundModes</key><array><string>audio</string></array> в Info.plist, и вы должны убедиться, что аудио сеанс активен / запущен / что угодно, прежде чем переключать приложения (предполагается, что вы не будете внезапно начинать запись / воспроизведение музыки / что угодно, когда ваше приложение находится в фоновом режиме),

В документах говорится, что "аудио" позволяет воспроизводить звук в фоновом режиме, но, вероятно, это также относится к записи звука. Если это не работает, есть несколько вещей, которые вы можете попробовать:

  • Установите оба "voip" и "аудио".
  • Воспроизведение тишины (это может быть проще всего сделать с помощью Audio Queue API).

У вас есть "applicationDidEnterBackground:" в вашем делегате приложения. Я почти уверен, что где-то читал (что не могу найти), что вам нужно определить его, чтобы ios распознал, что вы поддерживаете фоновые режимы. Вам не нужно ничего реализовывать в этом.

например

- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
Другие вопросы по тегам