Wesley Basson
Wesley Basson

Reputation: 167

How does one upload an m4a audio file to Firebase Storage using react-native and expo?

I am building an app using react-native and expo. One feature of the app allows a user to record audio and then upload it to Firebase Storage. I manage to successfully record the audio and also manage to retrieve the cached file as a blob but when trying to upload it to Firebase Storage it fails with error code 400, "Bad Request. Could not create object". What baffles me is that I use the same process to upload images which works perfectly. Why does it fail for audio files?

I manage to record the audio successfully and I retrieve the cached file (as a blob) using XMLHttpRequest. The resultant blob that outputs when I log it to the console looks something like this:

    Blob {
        "_data": Object {
            "blobId": "lengthy blob id",
            "name": "recording-XXXXXX.m4a",
            "offset": 0,
            "size": 371097,
            "type": "audio/x-m4a",
        },
    }

When I try uploading to Firebase Storage using ref.put(blob) it returns with a 400 error: "Bad Request. Could not create object". I have also tried supplying the contentType as part of the metadata to see if that will make a difference but to no avail.

This is how I fetch my file:

    const blob = await new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.onload = () => {
            resolve(xhr.response);
        };
        xhr.onerror = (e) => {
            reject(new TypeError('Network request failed'));
        };
        xhr.responseType = 'blob';
        xhr.open('GET', uri, true);
        xhr.send(null);
    });

To upload the blob to Firebase Storage I do the following:

    const clientuid = 123;
    const siteid = 'ABC';
    const audioName = `${Date.now}.m4a`;
    this.setState({ uploading: true });
    const ref = firebase.storage().ref().child(`audio/${clientuid}/${siteid}/${audioName}`);
    ref.put(blob)
    .then(async (snapshot) => {
        const fullUrl = await snapshot.ref.getDownloadURL();
        // Upload the Url to Firebase realtime database...
        Alert.alert('Upload Successful');
    .catch((error) => {
        console.log(error.serverResponse);
        Alert.alert('Failed to create object!');
    })
    .finally(() => {
        blob.close()
        this.setState({ uploading: false });
    });

The upload fails with the following error.serverResponse:

    {
       "error": {
          "code": 400,
          "message": "Bad Request. Could not create object",
          "status": "CREATE_OBJECT"
       }
    }

Upvotes: 1

Views: 2386

Answers (2)

I think you have to check the size of blob

if (blob.size >= 2000000) {
   return;
}

This is my work:

const blob = await new Promise<Blob>((resolve, reject) => {
  const xhr = new XMLHttpRequest();
  xhr.onload = function () {
  resolve(xhr.response);
  };
  xhr.onerror = function (e) {
    reject(new TypeError("Network request failed"));
  };
  xhr.responseType = "blob";
  xhr.open("GET", uri[i], true);
  xhr.send(null);
});
  
 if (blob.size >= 2000000) {
   return urls;
 }
  
 if (auth.currentUser) {
    const fileRef = ref(
      storage,
      auth.currentUser.uid +
      "/recordings/" +
      diaryId
    );
    await uploadBytes(fileRef, blob)
    .then((snapshot) => {
         console.log("Uploaded");
    })
    .catch((err) => {
         console.log(err);
     });
     const url = await getDownloadURL(fileRef);
     console.log(url);
}

Upvotes: 0

Tobias Ramm
Tobias Ramm

Reputation: 71

In your case I think you can also create the blob by fetching the file with the file path.

let res = await fetch(filePath);
let blob = res.blob

In my case this always works.

Upvotes: 1

Related Questions