iOS Voip Socket не будет работать в фоновом режиме - PullRequest
21 голосов
/ 06 июля 2011

Я получаю 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. Я работаю на устройстве, а не на симуляторе. Это все еще не работает, поэтому я не знаю, в чем может быть моя проблема. Я, наверное, просто сделал что-то глупое, но в интернете почти нечего проверять.

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

Ответы [ 5 ]

28 голосов
/ 12 сентября 2011

Если вы хотите, чтобы ваше приложение 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 секунд снова отправит ответ. продолжайте делать это, ваше приложение проснется навсегда.

5 голосов
/ 14 августа 2011

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

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

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

все остальные упомянутые данные по-прежнему корректны:

  • kCFStreamNetworkServiceTypeVoIP
  • 'info.plist' UIBackgroundModes: voip, audio
  • 'info.plist 'UIRequiresPersistentWifi key
  • НЕ будет работать над симулятором
3 голосов
/ 30 августа 2012

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

  1. wifi -> 3g
  2. 3g -> wifi

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

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

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

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

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

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

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

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

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

, например

- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
0 голосов
/ 29 июля 2011

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

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

  • Установить «voip» и «audio».
  • Воспроизвести тишину (это может быть проще всего сделатьс API аудио-очереди).
...