iOS Voip Socket ne fonctionnera pas en arrière-plan

j'obtiens une socket VOIP pour fonctionner en arrière-plan dans une application iOS.

ma connexion fonctionne très bien, mais elle ne se réveillera pas lorsque mon application passera à l'arrière-plan. Si j'ouvre l'application, elle répond à tous les messages qu'elle a reçus pendant qu'elle dormait.

j'ai mis en place mon stream comme ceci:

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);

Puis mon callback est mis en place comme ceci:

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" est appelé lorsque je reçois des données et que l'application est ouverte, mais il ne fait pas si l'application est réduite. Lorsque l'application est de retour, cependant, il traite toutes les données qu'il a reçues tout en minimisant.

j'ai ajouté l'étiquette voip à l'info.plist. My CFReadStreamSetProperty returns true. Je fonctionne sur un dispositif pas un simulateur. Ça ne marche toujours pas, donc je ne sais pas quel pourrait être mon problème. J'ai probablement fait quelque chose de stupide, mais il n'y a presque rien en ligne pour vérifier mon code.

EDIT: Je ne peux tester aucune des réponses parce que Je ne travaille plus sur ce projet et je n'ai pas accès à un sdk mac/iOs. Si quelqu'un ayant un problème similaire a trouvé l'une des réponses ci-dessous utile, Faites-le moi savoir et je voterai la meilleure réponse.

21
demandé sur Joel 2011-07-06 22:59:02

5 réponses

si vous voulez laisser votre application VOIP fonctionner en arrière-plan , sauf ces paramètres de base dans le fichier plist, vous avez besoin d'une socket TCP qui est la propriété de VOIP, que le système iOS prendra soin de cette socket pour vous, lorsque votre application entrer en arrière-plan , tout était "sommeil" sauf que socket tcp. et si le serveur VOIP envoie quelques données pensé que la socket TCP, votre application sera éveillé pendant 10 Secondes. pendant ce temps, vous pouvez envoyer une notification locale.

Seul Le Protocole Tcp la socket peut être configurée comme une socket VOIP. Mais de je sais, la plupart des applications VOIP sont basées sur UDP socket. si vous ne voulez pas séparer la socket de contrôle de la socket de données. vous devez créer une autre socket tcp qui se concentre sur "éveiller" votre application , et de mon expérience personnelle, il est très difficile de garder ce signal "éveillé" et le vrai signal de contrôle SIP synchroniser, l'application manque toujours la demande d'invitation sip.

donc, la meilleure façon est de séparer le contrôle sip simple à partir de la socket de données UDP, faire comme une socket tcp , c'est la meilleure solution, mais ne jamais utiliser la socket tcp pour transférer des données vocales.

une autre manière sale: garder l'application éveillée tout le temps. Comme je l'ai dit , chaque TCP simple l'application reçue pensait que 'VOIP' TCP socket, va garder l'application éveillée pendant 10 secondes, donc à la fin de cette durée(après 9 secondes) , vous pouvez envoyer une réponse au serveur pour demander un autre signal , lorsque le prochain signal est arrivé, le application sera réveillé à nouveau, après 9 secondes, envoyer la réponse à nouveau. continuez comme ça, votre application se réveillera pour toujours.

28
répondu Joe Qian 2011-09-12 19:44:19

j'étais coincé avec le même scénario.

Mon problème est que j'ai configuré plus d'une socket comme socket Voip.

vous pouvez voir à les documentations D'Apple sur la voip ce qu'ils disent:

"Configurer des sockets de L'application pour L'utilisation VoIP"

je suppose qu'ils ne réveillent votre application que selon une seule prise.

toutes les autres choses mentionnées sont toujours correct:

  • kCFStreamNetworkServiceTypeVoIP
  • ' info.Plust ' UIBackgroundModes: voip, audio
  • ' info.plist' Uirequirequirespersistentwifi key
  • ne fonctionne PAS avec simulateur
5
répondu avishic 2011-08-14 13:45:04

je suis aussi confronté au même problème. mais dans mon cas, tout fonctionne bien, à moins que le réseau ne change. J'ai utilisé la classe apple "reachability" pour détecter les changements de réseau. si l'application est en arrière-plan jusqu'à un certain moment ma socket fonctionne même si j'ai changé manuellement mon réseau pour les suivants.

  1. wifi - > 3G
  2. 3G -> wifi

après un certain temps, disons encore im essayant commutateur de réseau manuellement. rien n'est arrivé il semble que mon application ne détecte pas changements de réseau. J'ai lu le doc d'apple ci-dessous. je suis sûr que faire mal (ou) disunderstood étape 3 et 6.

il y a plusieurs exigences pour la mise en oeuvre D'une application VoIP:

1. Ajoutez la clé UIBackgroundModes aux informations de votre application.dossier plist. Définissez la valeur de cette clé à un tableau qui comprend la voip chaîne.

  1. configurer une des sockets de l'application pour une utilisation VoIP.

  2. Avant de passer à l'arrière-plan, appel la méthode setKeepAliveTimeout: handler: pour installer un handler à exécuter périodiquement. Votre application peut utiliser ce gestionnaire pour maintenir sa connexion au service.

  3. configurez votre session audio pour gérer les transitions vers et depuis l'utilisation active.

5. Pour assurer une meilleure expérience utilisateur sur iPhone, utilisez le cadre de téléphonie de base pour ajuster votre comportement en relation avec les appels téléphoniques basés sur la téléphonie cellulaire; voir cadre de téléphonie de base Référence.

  1. pour assurer de bonnes performances pour votre application VoIP, utilisez le cadre de Configuration du système pour détecter les changements de réseau et permettre à votre application de dormir autant que possible.
3
répondu user1586900 2012-08-31 10:51:51

Vous pourriez avoir besoin de définir <key>UIBackgroundModes</key><array><string>audio</string></array> en Info.plist, et vous devez vous assurer que la session audio est active/running/whatever avant de changer d'application (l'hypothèse est que vous ne commencerez pas soudainement à enregistrer/jouer de la musique/whatever lorsque votre application est à l'arrière-plan).

La documentation dire que "audio" vous permet de lire l'audio en arrière-plan, mais probablement cela s'applique aussi à l'enregistrement audio. Si cela ne fonctionne pas, il ya quelques choses que vous pourriez à essayer:

  • réglez à la fois" voip "et"audio".
  • Play silence (cela pourrait être plus facile à faire avec L'API de file D'attente Audio).
0
répondu Sneakyness 2011-07-28 21:38:36

avez-vous une