Kutay Demireren Kutay Demireren - 22 days ago 7
iOS Question

Can't upload audio file through server using Alamofire

class VoiceRecogViewController: UIViewController, AVAudioPlayerDelegate, AVAudioRecorderDelegate {


var audioPlayer: AVAudioPlayer?
var audioRecorder: AVAudioRecorder?
var error: NSError?
var soundFileURL: URL?
var soundFilePath: String = ""
var data : NSData?

@IBOutlet weak var startRocordButton: UIButton!
@IBOutlet weak var stopRecordButton: UIButton!
@IBOutlet weak var playRecordButton: UIButton!
@IBOutlet weak var continueButton: UIButton!

override func viewDidLoad() {

super.viewDidLoad()
playRecordButton.isEnabled = false
stopRecordButton.isEnabled = false

let dirPaths =
NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask, true)

let docsDir = dirPaths[0]
soundFilePath = (docsDir as NSString).appendingPathComponent("sound.wav")
soundFileURL = URL(fileURLWithPath: soundFilePath)

let recordSettings = [AVEncoderAudioQualityKey: AVAudioQuality.min.rawValue,
AVEncoderBitRateKey: 16,
AVNumberOfChannelsKey: 2,
AVSampleRateKey: 44100.0] as [String : Any]

let audioSession = AVAudioSession.sharedInstance()
try! audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: [])
try! audioSession.setActive(true)

if let err = error {
print("audioSession error: \(err.localizedDescription)")
}

do {
audioRecorder = try AVAudioRecorder(url: soundFileURL!,
settings: recordSettings as [String : AnyObject])
} catch {
audioRecorder = nil
}

audioRecorder?.prepareToRecord()

// Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


@IBAction func startRecord(_ sender: AnyObject) {
if audioRecorder?.isRecording == false {
playRecordButton.isEnabled = false
startRocordButton.isEnabled = false
stopRecordButton.isEnabled = true
audioRecorder?.record()
}
}

@IBAction func stopRecord(_ sender: AnyObject) {
stopRecordButton.isEnabled = false
playRecordButton.isEnabled = true
startRocordButton.isEnabled = true

if audioRecorder?.isRecording == true {
audioRecorder?.stop()
} else {
audioPlayer?.stop()
}
}

@IBAction func playRecord(_ sender: AnyObject) {
if audioRecorder?.isRecording == false {
stopRecordButton.isEnabled = true
startRocordButton.isEnabled = false
}

do {
try audioPlayer = AVAudioPlayer(contentsOf: soundFileURL!)
audioPlayer?.delegate = self
audioPlayer?.prepareToPlay()
audioPlayer?.play()
} catch {
print("audioPlayer error")
}
}

@IBAction func continueRegist(_ sender: AnyObject) {

let headers: HTTPHeaders = ["Authorization": "Token ___(**token**)_____",
"Accept": "application/json"]

data = NSData (contentsOf: soundFileURL!)

let parameters: Parameters = ["from_account_id": "3",
"to_account_id": "4",
"file": data!,
]

let URL = "http://leaofımjpüsmfweüdıpckfw"

Alamofire.request(URL, method: .put, parameters: parameters, headers: headers).responseJSON { response in
if let data = response.result.value {
print(data)
}
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
startRocordButton.isEnabled = true
stopRecordButton.isEnabled = false
}

func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
print("Audio Play Decode Error")
}

func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
}

func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
print("Audio Record Encode Error")
}


I shared my code above. Here the point is recording audio as .wav, playing it in app and in continueRegist part I want to call put method with alamofire and upload the audio to our amazons3server. Recording and playing audio part is totally working. The problem is in the method continueRegist. After calling the method, I am getting the correct response, it looks successful. Then, I am checking it from the url of our s3 server. The audio seems like uploaded but when I download and play it, it is not working. I could not figure out the where problem is.

Also, when I try to upload from Postman with selecting file and giving the right form data information, I can listen the sound I uploaded to the s3 server. What might be wrong here?

Below you can find my request through Postman:

Body:
body

I forgot to choose the file when I am taking the screenshot but it is simply a .wav file.

Headers
headers

Please do not hesitate to ask me questions those does not satisfy you.

Hope you can help me.

Thanks!

Answer

The problem is in your Alamofire Request: You are building a JSON with the audio data in the JSON. However, you can check in Postman the HTTP code(top right/under send) that the request is Multi Part Form Data.

How to implement a multipart Alamofire: It should be something similar to that I am not sure about appendBodyPart statements. They depend on your case

let audioData: NSData = ...//should be loaded from the file

Alamofire.Manager.upload(.PUT,
                          URL,
                          headers: headers,
                          multipartFormData: { multipartFormData in
                            multipartFormData.appendBodyPart(data: "3".dataUsingEncoding(NSUTF8StringEncoding), name: "from_account_id")
                            multipartFormData.appendBodyPart(data: "4".dataUsingEncoding(NSUTF8StringEncoding), name: "to_account_id")
                            multipartFormData.appendBodyPart(data: audioData, name: "file", fileName: "file", mimeType: "application/octet-stream")
                            },
                          encodingCompletion: { encodingResult in
                            switch encodingResult {

                            case .Success(let upload, _, _):
                                upload.responseJSON { response in

                                }

                            case .Failure(let encodingError):
                                // Error while encoding request:
                            }
})
Comments