Sending an audio recording from js to an actix-web server to save to disk

Currently trying to send some recorded audio from the browser to an actix-web server, and trying to save it to disk in a manner that results in a playable track from a generic media player. I am finding this difficult to do, especially because I have never worked with media before. I am basing whatever I am doing on. a combination of some googling and some GPTing.
The problem: A file does seem to be saved to disk. It is a non-zero size file however it does not seem playable in VLC media player.
The script to send the recording to the actix-web server:

 const blob = new Blob(chunks, { type: "audio/mp3" });
      const audioURL = URL.createObjectURL(blob);
      const audio = new Audio(audioURL);

      // create a button
      let button = document.createElement("BUTTON");
      // creating text to be
      //displayed on button
      let text = document.createTextNode("Play recording ", audio_rec_num + 1);
      button.appendChild(text);
      button.setAttribute("num", audio_rec_num);

      audio_rec_num++;
      document.body.appendChild(button);
      button.addEventListener("click", function () {
        let num = Number(button.getAttribute("num"));

        // audio_chunks[num].play();

        // Create FormData object to send the audio data
        const formData = new FormData();
        formData.append("audio", blob, "recorded_audio.mp3");

        // Send the audio data to the server using fetch or XMLHttpRequest
        fetch("http://127.0.0.1:8080/track_sample", {
          method: "POST",
          body: formData,
        })
          .then((response) => {
            if (response.ok) {
              console.log("Audio sent successfully");
            } else {
              console.error("Failed to send audio");
            }
          })
          .catch((error) => {
            console.error("Error sending audio: ", error);
          });
      });

The handler receiving the data:

async fn track_sampler(req_body: web::Bytes) -> impl Responder {
    println!("track sampler hit");
    let audio_data = req_body.to_vec();
    println!("Received audio data with length: {}", audio_data.len());

    // Save the audio data to a WAV file
    let file_path = "received_audio.mp3";
    let mut file = match File::create(file_path) {
        Ok(file) => file,
        Err(_) => return HttpResponse::InternalServerError().finish(),
    };

    // Write the bytes of the audio file to the file on disk
    if let Err(_) = file.write_all(&audio_data) {
        return HttpResponse::InternalServerError().finish();
    }
    println!("done");
    // Return a success response
    HttpResponse::Ok().body("Audio file uploaded successfully")
}

I just need some clear pointers to be able to implement this. I don't necessarily need code, but that could be super helpful as well. What am I doing wrong ? I know I am saving it incorrectly, but how do it 'correctly' ?

Note : I do not wish to save the audio to disk directly from the JS

Using actix-multipart — server-side Rust // Lib.rs makes this a lot easier. You can find some example code in examples/forms/multipart at master · actix/examples · GitHub.

1 Like

Hi,
This appears to be exactly what I was looking for. Had posed the same question on SF and they got back to me with the actix-multipart as well. Thanks a lot for taking the time out! @firebits.io .
For anybody else who is stuck in my position:

Thanks for letting us know it was solved, but also please let us know about cross-posts ahead of time.

1 Like

I will keep that in mind. Thanks.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.