我已经在 iOS Alexa 应用程序上工作了一段时间,但我正在努力将麦克风音频作为流发送到 AVS API。
我成功地预先录制了一个音频样本并将其作为一个整体发送并得到响应。
我只想知道如何使用 NSURLSession http/2 连接将数据流式传输到 AVS。
这是我现在正在做的代码片段:
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()
}
此函数每 320 字节的音频数据调用一次,因为这是亚马逊推荐的流式传输大小:)
问候!