[Clos] Envoyer un fichier txt ou audio par paquet

Am_MeAm_Me Membre
juillet 2013 modifié dans API UIKit #1

Voilà  j'ai besoin d'avoir des renseignement à  propos de : Comment envoyer un fichier audio par paquet


 


Je m'explique actuellement j'utilise le AudioQueu Recorder pour enregistrer mon audio


 


Je voudrai envoyer des petits bouts d'audio par packet et non pas tout d'un coup


 


Vers quelles documentations, classes, api, tutoriels devrais-je me tourner ???


 


MAJ : Ce sujet a été clos : Une nouvelle question a été ouverte : http://forum.cocoacafe.fr/topic/11303-nsurlrequest-nsinputstream-et-nsmutabledata/


Réponses

  • Quel est l'objectif ? Qui va recevoir le paquet et pour en faire quoi ?


    J'ai déjà  bien joué avec les paquets en sortie de AudioQueues pour faire du stream ou de l'encodage, je dois pouvoir t'aider mais un peu plus de détail sur ce que tu cherche à  faire serait utile pour ne pas partir dans tous les sens.


  • Am_MeAm_Me Membre
    juillet 2013 modifié #3

    C'est un peu du stream en gros j'envoi un bout de fichier audio et en retour j'ai du XML qui contient une string


    C'est de la reco vocale en résumé.


     


    Et actuellement j'utilise une classe déjà  programmé par quelqu'un pour l'enregistrement : AudioQueue Recorder


     


    MAJ : Sur l'audio queue je comprend le principe de AQRCallBAck etc... mais si tu me demande demain recréer moi la classe AudioQueue je  :o


    Et je suppose que c'est dans la fonction callBack que l'on doit utiliser pour effectuer une connexion pour envoyer le petit paquet.


  • Oula, entre un paquet et un bout de fichier audio il y a une grosse différence quand même. En sortie du CallBack de ton AQ tu as une frame qui est généralement une fraction de seconde. T'aura même pas un phonème dedans, ta reconnaissance vocale ne pourra rien faire avec.


     


    Je n'ai jamais fait de reconnaissance vocale mais perso je ferais plus un enregistrement complet local, quand l'utilisateur presse sur OK (ou que tu détecte la fin de la dictée avec un processing plus poussé), tu fini ton enregistrement et tu envois la phrase complète sur ton serveur.


     


    La reconnaissance vocale à  besoin de toute la phrase pour fonctionner (pour être capable de prendre en compte les intonations ainsi que le contexte).


     


    C'est du moins comme cela que je comprends la chose.


    Pour optimiser tu peux éventuellement envoyer des samples en court de route mais la traduction ne se fera qu'une fois la fin de la phrase reçu.


     


    Tu travail sur un projet pro ou universitaire ? ça me semble bizarre quand même ton approche.


  • Am_MeAm_Me Membre
    juillet 2013 modifié #5

    Alors je me suis mal exprimé dsl


     


    Mon appli fait déja ce que tu dis


     Je n'ai jamais fait de reconnaissance vocale mais perso je ferais plus un enregistrement complet local, quand l'utilisateur presse sur OK (ou que tu détecte la fin de la dictée avec un processing plus poussé), tu fini ton enregistrement et tu envois la phrase complète sur ton serveur.

     



     


    Mais la je passe à  la vitesse sup. Je dois envoyer alors pour moi bout audio = buffer disons que je le vois comme ca


     


     T'aura même pas un phonème dedans, ta reconnaissance vocale ne pourra rien faire avec.

     



    Ne t'inquiète pas pour le serveur il gère ca :D


     


    Tu travail sur un projet pro ou universitaire ? ça me semble bizarre quand même ton approche. 

     



     


    Mon stage étant fini je bascule sur un contrat normal et ma mission est que  je dois mettre en place le mode 'streaming' vu que le mode normal en gros Attendre que l'enregistrement soit fini puis tout envoyer est trop lent :/


  • Pour moi vous allez dans un mur mais sinon ce qu'il va falloir que tu fasse c'est que dans le CallBack de l'AQ tu ai un système qui va empiler tes buffer dans une file FIFO.


     


    Ensuite, tu dois avoir un mécanisme de polling dans un thread totalement distinct qui viens dépiler tes buffer de la file (par le bas donc) et les envoyer sur le réseau par le mécanisme que tu souhaite.


     


    Enfin quand le buffer est envoyé, tu le place dans une autre file qui sert de pile de buffer à  réutiliser. Lorsque ton AQ te demande un buffer à  utiliser pour le prochain tour, tu récupère un dispo dans cette pile et si elle est vide tu en crée un neuf.


     


    Mais t'as intérêt à  avoir une bonne gestion de ta relation client serveur et du HTTP pipeline pour essayer de rester soft sur les communication. De plus je pense que tu va être obliger de regrouper les paquets et ne les envoyer que toutes les X secondes si tu ne veut pas faire un déni de service sur ton serveur.


     


    Par sécurité il va également falloir que tu indexe tes numéro de frame (attentions aux valeurs max) car tu n'a aucune garantie que ta requête 1 soit bien interprété sur le serveur avant la 2 sauf à  faire un envois synchrone qui serait beaucoup plus lent.


  • Am_MeAm_Me Membre
    juillet 2013 modifié #7

    Ok merci de m'avoir donné le mécanisme, même si je suis un peu perdu de base sur l'AQ.


    Je sens comme tu dis que je fonce dans un mur mais j'ai pas le choix :/ . :o


     


    MAJ : Pour pas te mentir j'ai juste survoler la classe qui me permet d'enregistrer.


    De base je voulais faire ma propre classe mais les histoires de buffers etc .. m'ont .... 


    Donc je me suis dit que je devais prendre une classe déjà  faites.


  • Bah t'as toutes les clefs pour le faire là , mais j'espère que les gens qui ont imaginé "la vitesse supérieure" savent où ils mettent les pieds, ça sent mauvais ton histoire ^^


     


    C'est quelle boite qui commandite ce dev ? Enfin si c'est pas confidentiel.


     


    J'ai du code qui fait grosso modo ce genre de chose mais je ne peux pas le partager. C'est pas hyper complexe à  faire ni même très long (jusqu'à  la partie pile de frame en tout cas). ça demande juste un peu de test pour comprendre où tu met les pieds.


  • Petite boite travaillant avec un labo ;) je ne peux pas dire de nom


    Bah voilà  pourquoi j'ai 1 mois pour le faire :/


    J'ai un ingénieur qui m'aide, mais qui n'est pas présent jusqu'à  la semaine prochaine et je suis totalement coincé en quelque sorte


  • Am_MeAm_Me Membre
    juillet 2013 modifié #10

    En fait je viens d'apprendre que pour envoyer l'audio je devais passer par le mode chunk


     


    Je ne comprend toujours pas comment envoyer ces paquets mais bon tout ira bien  :o


     


    Et d'ailleurs je suis tombé sur ca Write to output stream sur la doc d'Apple ca me serviva ? Ou ce n'est pas du tout ce que je veux faire


  • Donc ton serveur ne fait pas d'analyse partiel. Il supporte la réception en petit bout et assemble le tout ensuite.


     


    Pour les output stream je ne les maitrise pas trop mais tu dois pouvoir faire quelque chose avec je pense (ça doit pouvoir remplacer mon système de pile).


  • laudemalaudema Membre
    juillet 2013 modifié #12

    Attention, la documentation que tu mets en lien est pour Mac OS, les communications réseau sont légèrement différentes pour iOS je crois savoir (je connais pas iOS).


    Il est peut être intéressant dans ton cas d'utiliser UDP plutôt que TCP/IP puisque la vitesse est la raison de ton travail, mais peux tu perdre un paquet de ci de là  ?


    Avec Mac OS le plus simple, pour utiliser les NSStream, est de les créer avec des CFStream (ou plus bas niveau encore) puis de les "caster" en objets Cocoa.


    Pour iOS et UDP ça semble toujours le cas...




  • Attention, la documentation que tu mets en lien est pour Mac OS, les communications réseau sont légèrement différentes pour iOS je crois savoir (je connais pas iOS).


    Il est peut être intéressant dans ton cas d'utiliser UDP plutôt que TCP/IP puisque la vitesse est la raison de ton travail, mais peux tu perdre un paquet de ci de là  ?


    Avec Mac OS le plus simple, pour utiliser les NSStream, est de les créer avec des CFStream (ou plus bas niveau encore) puis de les "caster" en objets Cocoa.


    Pour iOS et UDP ça semble toujours le cas...




     


    Pour faire de la reco vocale ça me semble être une très mauvaise idée de recommander de l'UDP. Ils cherchent pas du tout à  faire du temps réel ici. Certes la vitesse est importante mais perdre des paquets n'est pas acceptable en reconnaissance vocal. De plus leur service web est basé sur HTTP comme dit précédemment, donc TCP.


     


    Toujours vu que leur service est basé sur HTTP, c'est pas dit que le stream soient d'une grande utilité.

  • En fait comme dis Yoann c'est pas vraiement du temps réel en gros 


     


    Appli actuelle : Durée Audio = 10 secondes implique qu'il faut attendre environ un peu plus de 10 secondes juste pour la transcription et ajouter 2 secondes pour la trad donc après avoir enregistré ton audio tu dois poiroter


     


    Alors que la si Durée Audio = 10 secondes je ne retrouverai à  attendre 3 secondes à  5 par exemples


     


    Et faut que j'évite au maximum de perdre des paquets sur la routes :/


  • La solution tu l'as en gros, maintenant c'est à  toi d'implémenter et de faire des tests de performance.


  • Merci pour la piste des paquets TCP j'ai trouvé des trucs à  voir ce que ca donne :D


  • Je reviens sur le sujet avant de le fermer :D car vous m'avez bien aidé


     


    J'ai sur moi le livre http://oreilly.com/iphone/excerpts/iphone-sdk/network-programming.html


     


    Et j'ai pu en conclure qu'il fallait que j'utilise le CFReadStream and CFWriteStream


     


    Suis-je sur la bonne voie ?


  • Pas besoin de descendre aussi bas. Je ne m'en suis jamais servis mais NSURLRequest permet de supporter un HTTPBodyStream qui va te permettre de démarrer avec un un NSInputStream initialisé avec tes données de départ puis d'y écrire ce que tu veux ensuite.


     


    ça t'évite de te frapper la réécriture des négo HTTP(S) avec des socket bas niveau.


  • Choqué :D


     


    Merci je savais pas que NSUrlRequest pouvait être utilisé pour des requetes en streaming  :o


     


    Merci


  • Bah faut lire la doc ^^


    Contrairement à  ce que bien des gens font croire, NSURLConnection et NSURLRequest répondre à  99.999% des problématiques HTTP. Dans la quasi totalité des cas, si tu te retrouve à  réinventer la roue c'est que tu as mal lu la doc.


     


    Tweaker NSURLConnection pour activer toute les optimisations, ouais, ça se fait assez souvent (et c'est le gros de AFNetwork & cie, ils ne font rien de transcendant). Mais repartir de 0, c'est assez peu probable.


  • Bah dis toi que j'étais à  2 doigts de recoder une classe de connexion :D


    merci


  • Am_MeAm_Me Membre
    juillet 2013 modifié #22

    Juste une petite question j'ai vu qu'avec le InputStream il me fallait lire dans un fichier


     


    NSInputStream *stream = [[NSInputStream alloc] initWithFileAtPath:filePath];


    [request setHTTPBodyStream:stream];


     


    Actuellement AQRCallBack ressemble à  ceci 



    static void AQRCallback (void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime,unsigned long frameSize,
      UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc)
    {
        RecordState *pAqData = (RecordState *) aqData;
        if (!pAqData->recording)
    return;
        
        if (inNumPackets == 0 && pAqData->dataFormat.mBytesPerPacket != 0)
            inNumPackets = inBuffer->mAudioDataByteSize / pAqData->dataFormat.mBytesPerPacket;
        
        if (AudioFileWritePackets(pAqData->audioFile, NO, inBuffer->mAudioDataByteSize, inPacketDesc, pAqData->currentPacket, &inNumPackets, inBuffer->mAudioData) == noErr)
        {
            pAqData->currentPacket += inNumPackets;
            if (pAqData->recording == 0) return;
            AudioQueueEnqueueBuffer (pAqData->queue, inBuffer, 0, NULL);
        }
    }

    Si je comprend bien je dois enregistrer le petit packet d'audio dans un fichier mais (uint8_t*)inBuffer->mAudioData (correspondant a ce bout d'audio si j'ai bien compris) ne dispose pas d'une fonction writeToFile  :o


    Donc au fond je ne pourrait jamais le récupérer  ???


     


     


    MAJ Et dans une classe que j'ai récupérer sur le net j'ai une méthode assez cool : 



    - (BOOL) startRecording: (NSString *) filePath
    {
    // file url
        [self setupAudioFormat:&recordState.dataFormat];
        CFURLRef fileURL =  CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *) [filePath UTF8String], [filePath length], NO);
        // recordState.currentPacket = 0;
        
    // new input queue
        OSStatus status;
        status = AudioQueueNewInput(&recordState.dataFormat, (AudioQueueInputCallback)AQRCallback, &recordState, CFRunLoopGetCurrent(),kCFRunLoopCommonModes, 0, &recordState.queue);
        if (status) {CFRelease(fileURL); NSLog(@Could not establish new queue\n); return NO;}
        
    // create new audio file
        status = AudioFileCreateWithURL(fileURL, kAudioFileAIFFType, &recordState.dataFormat, kAudioFileFlags_EraseFile, &recordState.audioFile);
    CFRelease(fileURL); // thanks august joki
        if (status) {NSLog(@Could not create file to record audio\n); return NO;}
        
    // figure out the buffer size
        DeriveBufferSize(recordState.queue, recordState.dataFormat, 0.5, &recordState.bufferByteSize);

    // allocate those buffers and enqueue them
        for(int i = 0; i < NUM_BUFFERS; i++)
        {
            status = AudioQueueAllocateBuffer(recordState.queue, recordState.bufferByteSize, &recordState.buffers[i]);
            if (status) {NSLog(@Error allocating buffer %d\n, i); return NO;}
            
            status = AudioQueueEnqueueBuffer(recordState.queue, recordState.buffers[i], 0, NULL);
            if (status) {NSLog(@Error enqueuing buffer %d\n, i); return NO;}
        }

    // enable metering
        UInt32 enableMetering = YES;
        status = AudioQueueSetProperty(recordState.queue, kAudioQueueProperty_EnableLevelMetering, &enableMetering,sizeof(enableMetering));
        if (status) {NSLog(@Could not enable metering\n); return NO;}
        
    // start recording
        status = AudioQueueStart(recordState.queue, NULL);
        if (status) {NSLog(@Could not start Audio Queue\n); return NO;}
        recordState.currentPacket = 0;
        recordState.recording = YES;
        return YES;
    }

    Donc cette méthode écris en live sur le fichier donc cela résolve mon problème ?


  • J'ai peut être dit une connerie. Je n'ai pas fait attention au fait que NSURLRequest demande impérativement du NSInputStream qui est un type de stream assez spécifique, il demande à  avoir l'intégralité des données dès le départ... À voir s'il est capable de gérer un fichier qui est modifié en cours de route ou un NSMutableData (NSMutableData sur lequel tu as appendBytes:length: pour ajouter tes inBuffer->mAudioData.


     


    J'ai pas trop le temps de tester mais tu va peut-être être hors limite de l'utilisation des classes HTTP de Cocoa. À voir ce que tu peux tweaker. Je te conseil de rouvrir un post sur le sujet NSURLRequest. NSInputStream et mutableData pour ne parler que de ça, voir ce que les gens ont trouvé comme méthode. Ce n'est pas une problématique propre qu'à  l'audio.


Connectez-vous ou Inscrivez-vous pour répondre.