Search code examples
iosswiftaudioamazon-s3alamofire

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!


Solution

  • 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:
                                }
    })