David
David

Reputation: 151

How to upload recording file from Expo-av via Axios?

I am trying to upload a file recorded using expo-av via an Axios post request to my server. Forgive me, I am a Python backend dev so I am not that familiar with JS or Axios. I have tried various solutions but can't get anything working.

The code I am using for the recording is this, mostly straight from the Expo docs (the recording element) and it is working fine (the audio file gets created by the simulator, e.g. a .caf file for iOS simulator)

import * as React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { Audio } from 'expo-av';

export default function App() {
  const [recording, setRecording] = React.useState();

  async function startRecording() {
    try {
      console.log('Requesting permissions..');
      await Audio.requestPermissionsAsync();
      await Audio.setAudioModeAsync({
        allowsRecordingIOS: true,
        playsInSilentModeIOS: true,
      }); 
      console.log('Starting recording..');
      const { recording } = await Audio.Recording.createAsync(
         Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY
      );
      setRecording(recording);
      console.log('Recording started');
    } catch (err) {
      console.error('Failed to start recording', err);
    }
  }

  async function stopRecording() {
    console.log('Stopping recording..');
    setRecording(undefined);
    await recording.stopAndUnloadAsync();
    const uri = recording.getURI(); 
    console.log('Recording stopped and stored at', uri);

  //My code for the upload
    const formData = new FormData();
    formData.append("attribute_x", "123");
    formData.append("attribute_y", "456");
    let soundFile = //NOT SURE WHAT THE ACTUAL SOUND FILE IS. The uri is just a string
    formData.append("recording", {uri: uri, name: 'soundfile.caf', type: 'audio/x-caf'});
    const response = await axios.post(my_url, formData, {
            headers: {
                'Content-Type': 'multipart/form-data',
                'X-CSRFToken': 'csrftoken',
            }
        })
  ... deal with the response...
  }



  return (
    <View style={styles.container}>
      <Button
        title={recording ? 'Stop Recording' : 'Start Recording'}
        onPress={recording ? stopRecording : startRecording}
      />
    </View>
  );
}

The request body I need to send should be:

{
  "attribute_x": 333,
  "attribute_y": 291,
  "recording": THE SOUND FILE
}

It's .caf for iOS and will be .mp4 for Android (defaults) but I can figure out how to deal with that myself. Just really pulling my hair out now with the upload/post request.

Thanks in advance.

Upvotes: 4

Views: 2671

Answers (1)

DevTheJo
DevTheJo

Reputation: 2477

I was unable to get it work with react-native, main cause is that multipart/form-data header wasn't set correctly and formdata.getHeaders() isn't defined in react-native.

Tried all that was tested here, but without success: https://github.com/axios/axios/issues/318

Solution: use https://github.com/sindresorhus/ky

const uri = recording.getURI();
const filetype = uri.split(".").pop();
const filename = uri.split("/").pop();
const fd = new FormData();
fd.append("audio-record", {
  uri,
  type: `audio/${filetype}`,
  name: filename,
});
await ky.post("audio/upload", {
  body: fd,
});

the headers will set automatically like with fetch api, and the boudary part will be provided !

Upvotes: 2

Related Questions