Подтвердить что ты не робот

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

EDIT: я не могу проверить ни один из ответов, потому что я больше не работаю над этим проектом и не имею доступа к mac/iOs sdk. Если кто-то с подобной проблемой нашел один из приведенных ниже ответов полезным, дайте мне знать, и я проголосую за его лучший ответ.

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

  • wifi → 3g
  • 3g → wifi

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

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

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

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

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

  • Настройте свой сеанс аудио для обработки переходов в активном режиме и из него.

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

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

Ответ 4

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

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

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

Ответ 5

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

например.

- (void)applicationDidEnterBackground:(UIApplication *)application
{
}