What libraries have to offer
React Native is getting more and more popular, however there are still areas that it doesn’t handle that well. I love sound, and everything it comes with, so naturally I wanted to play around, and check how React Native handles recording and playing sound.
Playing sound
It isn’t obvious! At the time of writing (v. 0.52-rc), there is nothing about playback support or recording in the react-native docs. Fortunately, the open-source community never sleeps! There are many libraries that add those functionalities, but I focused on the ones that are the most popular and are widely used.
React-native-sound
It was the first library I started to play around with. It seems really simple, has a small API and a good support for all the things one would like to do with sound (volume control, pausing, playing, setting time etc.). The great thing about this library is that it even supports playing sounds from the network. This option is not well documented, but to use it, we have to pass
null
as the second parameter, while creating a Sound
instance. It looks something like this:import Sound from 'react-native-sound'; const sound = new Sound('http://sounds.com/some-sound', null, (error) => { if (error) { // do something } // play when loaded sound.play(); });
The only downside is that it looks like the project is not being actively maintained, and there are 20 open pull-requests. Other than that I didn’t have any bigger problems with it so far.
React-native-video
This may seem like a weird choice but it isn’t. React-native-video is meant mostly for video playback, but as it turns out, a lot of people use it just to control sound.
This project has a bigger community behind it, and there are some functionalities that are not yet available or are not well supported in react-native-sound, like playing sounds in the background or access to events like onProgress, onLoadStart, onLoad, onPlay and others.
In this case, authors wanted to create something that is a bit more similar to HTML5 video specification. It works perfectly good with audio as well, since those two APIs are similar by design.
import Video from 'react-native-video'; // From documentation <Video source={{uri: "background"}} // Can be a URL or a local file. ref={(ref) => { this.player = ref }} // Store reference rate={1.0} // 0 is paused, 1 is normal. volume={1.0} // 0 is muted, 1 is normal. muted={false} // Mutes the audio entirely. paused={false} // Pauses playback entirely. resizeMode="cover" // Fill the whole screen at aspect ratio.* repeat={true} // Repeat forever. playInBackground={false} // Audio continues to play when app entering background. playWhenInactive={false} // [iOS] Video continues to play when control or notification center are shown. ignoreSilentSwitch={"ignore"} // [iOS] ignore | obey - When 'ignore', audio will still play with the iOS hard silent switch set to silent. When 'obey', audio will toggle with the switch. When not specified, will inherit audio settings as usual. progressUpdateInterval={250.0} // [iOS] Interval to fire onProgress (default to ~250ms) onLoadStart={this.loadStart} // Callback when video starts to load onLoad={this.setDuration} // Callback when video loads onProgress={this.setTime} // Callback every ~250ms with currentTime onEnd={this.onEnd} // Callback when playback finishes onError={this.videoError} // Callback when video cannot be loaded onBuffer={this.onBuffer} // Callback when remote video is buffering onTimedMetadata={this.onTimedMetadata} // Callback when the stream receive some metadata style={styles.backgroundVideo} /> // Later to trigger fullscreen this.player.presentFullscreenPlayer() // To set video position in seconds (seek) this.player.seek(0)
Recording sound
Recording is also not supported by default yet. Fortunately, there is a library called react-native-audio, that helps with that. The API is really simple. It basically allows just to start/stop recording, and specify where and how do we want to save our recording. There is no player that comes with this library, which means that probably you will need one of the above, to play recorded sounds.
This library allows us to control Sample Rate, Audio Quality, Channels, Audio Encoding, Metering (iOS only) and Audio Encoding Bit Rate (Android only). All the available encodings are listed in the react-native-audio documentation.
import { AudioRecorder, AudioUtils } from 'react-native-audio'; let audioPath = AudioUtils.DocumentDirectoryPath + '/test.aac'; AudioRecorder.prepareRecordingAtPath(audioPath, { SampleRate: 22050, Channels: 1, AudioQuality: "Low", AudioEncoding: "aac" });
What about Expo?
When developing with Expo, there is support for playing and recording sound, by default. Personally, I didn’t try it out, but the API seems well documented and simple. All the information on how to use it is available in the Expo SDK documentation.
const soundObject = new Expo.Audio.Sound(); try { await soundObject.loadAsync(require('./assets/sounds/hello.mp3')); await soundObject.playAsync(); // Your sound is playing! } catch (error) { // An error occurred! }
A thing to remember…
Because those libraries are using features that need permissions, e.g. microphone, there will be a need to edit platform specific files, like Info.plist and AndroidManifest.xml. Usually, library authors also remind about that in libs readme and provide a basic instructions on how to do it.
The state of playing and recording sound in react-native is okay, but of course, it could be better.
Maybe it’s not a great idea to build the next Spotify with react-native yet (at least unless you also have knowledge of each specific platform), but for a simple music player or radio app it will work just fine.