Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to download an audio file and play it using React Native Expo?

I have audio files hosted on a server that I'd like my app to access after authenticating. Users send a GET request which includes an authentication token, and the server returns the binary audio data.

As far as I can see there is no way to save this 'blob' as an audio file to the filesystem. The current implementation of fetch in react-native doesn't support blobs: link

... and the ideally-suited react-native-fetch-blob library isn't supported in expo either: link

Additionally I can see no way of streaming the audio file from the server. The included audio library with expo allows streaming of audio from a url (e.g. http://example.com/myaudio.mp3) however I can't see any way to attach an authorisation header to the request (e.g. "Authorization": "Bearer [my-token]").

Is there a way of achieving this, either by downloading and saving the audio blob, or streaming from a url with an authorisation header included in the request? I could detach my project from Expo but I'd like to leave that as a last-resort.

like image 634
Tom Avatar asked Jan 30 '23 22:01

Tom


1 Answers

Yes, it is. You need to use the Audio module exposed by expo to do it. Below are the steps that you have to follow to load and play an audio file from a given URL. I've also copied over the code for my component that is doing the same for me.

  • Load Audio module exposed by expo

    import { Audio } from 'expo'

  • Create a new sound Object from it

    soundObject = new Audio.Sound()

  • Asynchronously load your file

    await this.soundObject.loadAsync({ uri: this.props.source })

  • Once loaded play the loaded file using

    this.soundObject.playAsync()

Below is a simple component that I wrote for doing it -

import React, { Component } from 'react';
import { View, TouchableNativeFeedback } from 'react-native';
import { Audio } from 'expo';

class AudioPlayer extends Component {
  constructor(props) {
    super(props);
    this.state = { isPlaying: false };

    this.loadAudio = this.loadAudio.bind(this);
    this.toggleAudioPlayback = this.toggleAudioPlayback.bind(this);
  }

  componentDidMount() {
    this.loadAudio();
  }

  componentWillUnmount() {
    this.soundObject.stopAsync();
  }

  async loadAudio() {
    this.soundObject = new Audio.Sound();
    try {
      await this.soundObject.loadAsync({ uri: this.props.source /* url for your audio file */ });
    } catch (e) {
      console.log('ERROR Loading Audio', e);
    }
  }

  toggleAudioPlayback() {
    this.setState({
      isPlaying: !this.state.isPlaying,
    }, () => (this.state.isPlaying
      ? this.soundObject.playAsync()
      : this.soundObject.stopAsync()));
  }

  render() {
    return (
      <TouchableNativeFeedback onPress={this.toggleAudioPlayback}>
        <View style={this.props.style}>
          {this.props.children}
        </View>
      </TouchableNativeFeedback>
    );
  }
}

export default AudioPlayer;
like image 87
Fauzan Avatar answered Feb 05 '23 15:02

Fauzan