How to play an Android audio file in React Native

Here’s a quick tutorial to get you started playing an mp3 file in an Android app that was built using React Native. This tutorial was developed using Linux (Ubuntu 16.04), React Native 0.61.5, and the React Native Sound package 0.11.0.

First, make your project directory. Let’s call it AudioTmp. In a terminal window, do this:

npx react-native init AudioTmp
cd AudioTmp

All of the following commands assume you’ve got your terminal window open, and you’re standing in the root directory of your project (in AudioTmp, where App.js is located).

You’ll need some extra packages, so run these install commands:

npm install typescript@
npm install eslint@^5.0.0
npm install react-native-sound

Next, as described in the React Native Sound documentation, use the link command:

react-native link react-native-sound

This “links” the library where needed into the android and ios directories.

Now add an mp3 file to your Android project:

mkdir android/app/src/main/res/raw
cp john_bartmann_04_earning_happiness.mp3 android/app/src/main/res/raw

You can download a copy of John Bartmann’s “Earning Happiness” mp3 file here. It has a public domain license; let’s thank John Bartmann for making his cool “Earning Happiness” music open source (original source at Free Music Archive)!

Next, make the utils directory under your project root:

mkdir utils

Add a new file called SoundPlayer.js in the utils directory. Here’s the source for that:

/**
 * Really simple demo of https://www.npmjs.com/package/react-native-sound
 */
const Sound = require('react-native-sound');
/**
 * Audio credit:
 * https://freemusicarchive.org/music/John_Bartmann/Public_Domain_Soundtrack_Music_Album_One/earning-happiness
 * "Earning Happiness" by John Bartmann licensed under a CC0 1.0 Universal License
 * https://creativecommons.org/publicdomain/zero/1.0/
 */
const FILENAME = 'john_bartmann_04_earning_happiness.mp3';

class SoundPlayer {
    constructor(props) {
        console.log("SoundPlayer constructor");
    };
    stopSound() {
        console.log('SoundPlayer.stopSound');
        this.whoosh.stop();
        this.whoosh.release();
    }
    playSound() {
        console.log('SoundPlayer.playSound');
        let me = this;
        me.whoosh = new Sound(FILENAME, Sound.MAIN_BUNDLE, error => {
            if (error) {
                console.log('failed to load the sound', error);
                return;
            }
            // loaded successfully
            console.log(
                'duration in seconds: ' +
                me.whoosh.getDuration() +
                'number of channels: ' +
                me.whoosh.getNumberOfChannels()
            );
            me.whoosh.play(success => {
                if (success) {
                console.log('successfully finished playing');
                } else {
                console.log('playback failed due to audio decoding errors');
                }
            });
        });
    }
}
export default SoundPlayer;

Replace the code in App.js with this code:

/**
 * Simple demo of https://www.npmjs.com/package/react-native-sound
 * The app plays an included mp3 file when the user clicks on 'Play' button.
 * It stops the playback when the user clicks on the 'Stop' button.
 */
import React from 'react';
import {
  StyleSheet,
  View,
    Text,
  Button
} from 'react-native';

import {
  Colors
} from 'react-native/Libraries/NewAppScreen';

/** Keep all sound functionality in separate utils area */
import SoundPlayer from './utils/SoundPlayer';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.soundPlayer = new SoundPlayer();
    }

    onPlayPress() {
        console.log('onPlayPress method');
        this.soundPlayer.playSound();
    }

    onStopPress() {
        console.log('onPlayPress method');
        this.soundPlayer.stopSound();
    }

    render() {
        return (
        <View style={styles.body}>
            <Text style={styles.sectionTitle}>Click button to Play</Text>
            <View style={styles.buttonStyle}>
                <Button style={styles.buttonStyle}
                    onPress={this.onPlayPress.bind(this)}
                    title="Play"
                />
            </View>
            <Text style={styles.sectionTitle}>Click button to Stop</Text>
            <View style={styles.buttonStyle}>
                <Button buttonStyle={styles.buttonStyle}
                    onPress={this.onStopPress.bind(this)}
                    title="Stop"
                />
            </View>
        </View>
        );
    }
};

const styles = StyleSheet.create({
    body: {
        backgroundColor: Colors.white,
        flex: 1,
        flexDirection: 'column',
        justifyContent: 'center',
        backgroundColor: 'gainsboro'
    },
    sectionTitle: {
        fontSize: 24,
        fontWeight: '600',
        color: Colors.black,
        padding: 20,
        backgroundColor: 'gainsboro' /* See https://reactnative.dev/docs/colors */,
    },
    buttonStyle: {
        padding: 20,
        backgroundColor: 'gainsboro' /* See https://reactnative.dev/docs/colors */,
    }
});

export default App;

Run the Android Emulator:

emulator -no-snapshot -avd Galaxy_Nexus_API_28

Start your Metro server:

npx react-native start

Install the app in your Android Emulator:

npx react-native run-android

I see these warnings at my command line, but everything seems to work okay:

error React Native CLI uses autolinking for native dependencies, but the following modules are linked manually: 
  - react-native-sound (to unlink run: "react-native unlink react-native-sound")
This is likely happening when upgrading React Native from below 0.60 to 0.60 or above. Going forward, you can unlink this dependency via "react-native unlink <dependency>" and it will be included in your app automatically. If a library isn't compatible with autolinking, disregard this message and notify the library maintainers.
Read more about autolinking: https://github.com/react-native-community/cli/blob/master/docs/autolinking.md
info Running jetifier to migrate libraries to AndroidX. You can disable it using "--no-jetifier" flag.
Jetifier found 875 file(s) to forward-jetify. Using 8 workers...

Then it just works! You can hit the Play and Stop buttons to play the audio.

The source code for this project is available at github.

One remark: when I initially created this project, I didn’t use the link command, because the React Native documentation indicated it was not needed for version 0.60. However, that turned out to be untrue! You can save yourself time by doing it the way I’ve done it in this tutorial. When using link, the demo worked immediately, and I didn’t have to make any changes to gradle files.

Here’s a view of the demo app:

Audio Player using React Native

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Leave a Reply

Your email address will not be published. Required fields are marked *