2017-04-19 4 views
1

Je travaille sur une application iOS Alexa pour un certain temps, mais je me bats envoyer le signal audio du microphone comme un flux à l'API AVS.Comment flux audio à v20160207 API Service vocal Alexa dans iOS

je réussissais préenregistrement un échantillon audio et l'envoi que dans son ensemble et obtenir une réponse.

Je veux juste savoir comment je peux diffuser des données à AVS avec une NSURLSession http/2 connexion.

Voici un extrait de code ce que je fais maintenant:

func sendData() { 
     let request = NSMutableURLRequest(URL: NSURL(string: "https://avs-alexa-na.amazon.com/v20160207/events")!) 
     request.setValue("Bearer \(Settings.Credentials.TOKEN)", forHTTPHeaderField: "authorization") 
     request.HTTPMethod = "POST" 

     let boundry = NSUUID().UUIDString 
     let contentType = "multipart/form-data; boundary=\(boundry)" 
     request.setValue(contentType, forHTTPHeaderField: "content-type") 

     let bodyData = NSMutableData() 

     let jsonData = "{\"context\":[{\"header\":{\"namespace\":\"Alerts\",\"name\":\"AlertsState\"},\"payload\":{\"allAlerts\":[],\"activeAlerts\":[]}},{\"header\":{\"namespace\":\"AudioPlayer\",\"name\":\"PlaybackState\"},\"payload\":{\"token\":\"\",\"offsetInMilliseconds\":0,\"playerActivity\":\"IDLE\"}},{\"header\":{\"namespace\":\"Speaker\",\"name\":\"VolumeState\"},\"payload\":{\"volume\":25,\"muted\":false}},{\"header\":{\"namespace\":\"SpeechSynthesizer\",\"name\":\"SpeechState\"},\"payload\":{\"token\":\"\",\"offsetInMilliseconds\":0,\"playerActivity\":\"FINISHED\"}}],\"event\":{\"header\":{\"namespace\":\"SpeechRecognizer\",\"name\":\"Recognize\",\"messageId\":\"messageId-123\",\"dialogRequestId\":\"dialogRequestId-321\"},\"payload\":{\"profile\":\"CLOSE_TALK\",\"format\":\"AUDIO_L16_RATE_16000_CHANNELS_1\"}}}" 

     bodyData.appendData("--\(boundry)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
     bodyData.appendData("Content-Disposition: form-data; name=\"metadata\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
     bodyData.appendData("Content-Type: application/json; charset=UTF-8\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
     bodyData.appendData(jsonData.dataUsingEncoding(NSUTF8StringEncoding)!) 
     bodyData.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 

     bodyData.appendData("--\(boundry)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 

     bodyData.appendData("Content-Disposition: form-data; name=\"audio\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
     //  bodyData.appendData("Content-Type: audio/L16; rate=16000; channels=1\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
     bodyData.appendData("Content-Type: application/octet-stream\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
     bodyData.appendData(audioData!) 
     bodyData.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 

     bodyData.appendData("--\(boundry)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
     session = NSURLSession.sharedSession() 
     session.configuration.timeoutIntervalForResource = 60000 
     session.configuration.timeoutIntervalForRequest = 60000 

     let upload = session.uploadTaskWithRequest(request, fromData: bodyData) { (data, response, error) in 
      print("done") 
      if(data?.length > 0) { 
       print("break") 
      } 
      if let httpResponse = response as? NSHTTPURLResponse { 
       if let responseData = data, let contentTypeHeader = httpResponse.allHeaderFields["Content-Type"] { 

        var boundry: String? 
        let ctbRange = contentTypeHeader.rangeOfString("boundary=.*?;", options: .RegularExpressionSearch) 
        if ctbRange.location != NSNotFound { 
         let boundryNSS = contentTypeHeader.substringWithRange(ctbRange) as NSString 
         boundry = boundryNSS.substringWithRange(NSRange(location: 9, length: boundryNSS.length - 10)) 
        } 

        if let b = boundry { 
         let parts = self.parseResponse(responseData, boundry: b) 
         print("got parts") 
//      self.sendSynchronize() 
         self.successHandler?(data: responseData, parts:self.parseResponse(responseData, boundry: b)) 
        } else { 
         print("something went wrong") 
         self.errorHandler?(error: NSError(domain: Settings.Error.ErrorDomain, code: Settings.Error.AVSResponseBorderParseErrorCode, userInfo: [NSLocalizedDescriptionKey : "Could not find boundry in AVS response"])) 
        } 
       } 
      } 
     } 

     upload.resume() 
    } 

Cette get fonction appelée tous les 320 octets de données audio, car c'est la taille Amazon recommande pour le streaming :)

Greets!

+0

Toute @tomwyckhuys chance? Moi aussi frappé dans le même problème. J'ai également essayé de supprimer le terme de limite finale. –

Répondre

0

Vous devez send the JSON metadata headers only once, au début de la demande de dialogue (par exemple, le moment où le micro est ouvert et commence l'enregistrement).

Vous aurez également besoin d'utiliser la même valeur limite pour chaque fois que vous appelez votre méthode sendData pour le même flux. Utilisez le même flux HTTP/2 pour l'intégralité de la requête, ce qui signifie que vous devrez refactoriser votre méthode sendData "à l'envers" pour y répondre. Les exemples qui utilisent uploadTask: withStreamedRequest pourraient être utiles (que vous devrez probablement utiliser).

Je ne suis pas familier avec les API HTTP/2 de Swift, donc je ne sais pas si les cadres de continuation seront gérés pour vous, ou si vous aurez besoin de gérer cela vous-même, donc c'est quelque chose à surveiller. Bonne chance et j'espère que cela aidera.