🚀 Cross-platform audio playback for React Native — Play sound clips on iOS and Android with full TypeScript support and modern React Native architecture compatibility.
- 🎯 Cross-platform: Works on iOS and Android
- 📱 Modern Architecture: Full support for React Native's New Architecture (TurboModules)
- 🔤 TypeScript: Complete TypeScript definitions included
- 🎛️ Rich Controls: Play, pause, stop, seek, volume, pan, and looping
- 📁 Flexible Loading: Load from app bundle, local files, or network URLs
- 🔄 Multiple Players: Play multiple sounds simultaneously
- ⚡ Optimized: Minimal latency with preloading support
- 🛡️ Reliable: Battle-tested in production apps
📝 Note: This library focuses on audio clips playback, not streaming. For streaming audio, consider react-native-video or other dedicated streaming solutions.
iOS Implementation: Uses AVAudioPlayer for optimal performance and compatibility.
Android Implementation: Uses MediaPlayer with proper audio focus handling.
Feature | iOS | Android |
---|---|---|
Loading | ||
Load from app bundle | ✅ | ✅ |
Load from local files | ✅ | ✅ |
Load from network URLs | ✅ | ✅ |
Playback | ||
Play/Pause/Stop | ✅ | ✅ |
Playback completion callback | ✅ | ✅ |
Resume playback | ✅ | ✅ |
Reset to beginning | ❌ | ✅ |
Audio Control | ||
Volume control | ✅ | ✅ |
Pan (L/R stereo) | ✅ | ❌ |
Playback speed | ✅ | ✅ |
System Integration | ||
Get system volume | ✅ | ✅ |
Set system volume | ❌ | ✅ |
Advanced Features | ||
Loop control | ✅ | ✅ |
Exact loop count | ✅ | ❌ |
Seek to time position | ✅ | ✅ |
Get current position | ✅ | ✅ |
Get duration | ✅ | ✅ |
Get channel count | ✅ | ❌ |
Resource Management | ||
Explicit resource cleanup | ✅ | ✅ |
npm install react-native-sound
yarn add react-native-sound
This library supports both the old and new React Native architecture:
- ✅ Old Architecture: Uses traditional NativeModules
- ✅ New Architecture: Uses TurboModules for better performance
- ✅ Expo: Compatible with custom development builds (not Expo Go)
This usually indicates a linking issue. Try:
-
Clear build cache:
cd android && ./gradlew cleanBuildCache
-
Reset Metro cache:
npx react-native start --reset-cache
-
Clean and rebuild:
# iOS cd ios && rm -rf build && cd .. && npx react-native run-ios # Android cd android && ./gradlew clean && cd .. && npx react-native run-android
- Ensure audio files are added to Xcode project bundle
- Check that AVFoundation framework is linked (automatically handled by CocoaPods)
- Place audio files in
android/app/src/main/res/raw/
- Use lowercase filenames without spaces or special characters
- Clear build cache if encountering linking issues
Check out our enhanced example app with both remote and local audio playback:
- 📁
/example
- Full-featured demo application - 🎯 Remote URL audio playback
- 📱 Local bundled audio files
- 🎨 Modern UI with TypeScript
- 🎵 react-native-sound-playerview - Advanced audio player UI component
Save audio files in android/app/src/main/res/raw/
:
android/app/src/main/res/raw/
├── whoosh.mp3 ✅ Correct
├── button_click.wav ✅ Correct
└── my-sound.mp3 ❌ Use underscores: my_sound.mp3
Note: Use lowercase, underscored filenames. No subdirectories allowed.
- Open your project in Xcode
- Right-click your project → "Add Files to [PROJECT]"
- Select your audio files and ensure they're added to the app target
import Sound from "react-native-sound";
// Enable playback in silence mode (important for iOS)
Sound.setCategory("Playback");
// Load a sound file from the app bundle
const whoosh = new Sound("whoosh.mp3", Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log("Failed to load the sound", error);
return;
}
// Sound loaded successfully
console.log("Duration:", whoosh.getDuration(), "seconds");
console.log("Channels:", whoosh.getNumberOfChannels());
// Play the sound
whoosh.play((success) => {
if (success) {
console.log("Successfully finished playing");
} else {
console.log("Playback failed due to audio decoding errors");
}
});
});
// Audio controls
whoosh.setVolume(0.5); // 50% volume
whoosh.setPan(1); // Full right stereo
whoosh.setNumberOfLoops(-1); // Loop indefinitely
// Get current properties
console.log("Volume:", whoosh.getVolume());
console.log("Pan:", whoosh.getPan());
console.log("Loops:", whoosh.getNumberOfLoops());
// Seek to specific time
whoosh.setCurrentTime(2.5);
// Get current playback position
whoosh.getCurrentTime((seconds) => {
console.log("Current time:", seconds);
});
// Control playback
whoosh.pause(); // Pause playback
whoosh.stop(() => {
// Stop and rewind
whoosh.play(); // Play from beginning
});
// Always release resources when done
whoosh.release();
// From app bundle (most common)
const bundleSound = new Sound("sound.mp3", Sound.MAIN_BUNDLE, callback);
// From documents directory
const docSound = new Sound("sound.mp3", Sound.DOCUMENT, callback);
// From library directory
const libSound = new Sound("sound.mp3", Sound.LIBRARY, callback);
// From absolute path
const pathSound = new Sound("/path/to/sound.mp3", "", callback);
// From remote URL (iOS/Android only)
const urlSound = new Sound("https://example.com/sound.mp3", "", callback);
import { useEffect, useRef, useState } from "react";
import Sound from "react-native-sound";
const useSound = (filename: string) => {
const sound = useRef<Sound | null>(null);
const [isLoaded, setIsLoaded] = useState(false);
const [isPlaying, setIsPlaying] = useState(false);
useEffect(() => {
sound.current = new Sound(filename, Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log("Error loading sound:", error);
return;
}
setIsLoaded(true);
});
return () => {
sound.current?.release();
};
}, [filename]);
const play = () => {
if (sound.current && isLoaded) {
sound.current.play((success) => {
setIsPlaying(false);
});
setIsPlaying(true);
}
};
const stop = () => {
if (sound.current) {
sound.current.stop();
setIsPlaying(false);
}
};
return { play, stop, isLoaded, isPlaying };
};
- Preload sounds during app initialization to minimize playback delay
- Reuse Sound instances for multiple playbacks of the same file
- Avoid race conditions by ensuring sounds are loaded before calling
play()
- iOS: Uses
AVAudioSessionCategoryAmbient
to mix multiple sounds - Multiple playback: You can play several sound files simultaneously
- Background audio: Configure audio categories for background playback
Supports: AAC, AIFF, CAF, MP3, WAV, and more
Supports: 3GPP, MP4, MP3, AAC, OGG, FLAC, WAV, and more
- Android absolute paths: Use
/sdcard/
prefix (e.g.,/sdcard/Downloads/sound.mp3
) - Method chaining: Supported for setters (e.g.,
sound.setVolume(0.5).setPan(0.5).play()
)
Library | Purpose | Best For |
---|---|---|
react-native-video | Video & audio streaming | Streaming audio/video |
react-native-audio-toolkit | Advanced audio features | Recording & complex audio |
Expo Audio | Expo audio solution | Expo managed workflow |
@react-native-async-storage/async-storage | Storage | Persisting audio preferences |
- ✅ Playing sound effects and short audio clips
- ✅ Background music with simple controls
- ✅ Audio feedback for user interactions
- ✅ Cross-platform compatibility requirements
- ✅ TypeScript projects requiring type safety
- ❌ Audio streaming or long-form content
- ❌ Advanced audio processing or effects
- ❌ Audio recording capabilities
- ❌ Complex playlist management
We welcome contributions! Here's how you can help:
- 🐛 Bug fixes and stability improvements
- 📚 Documentation improvements and examples
- 🧪 Test coverage expansion
- 🚀 Performance optimizations
- 🆕 New platform support
- Fork and clone the repository
- Install dependencies:
npm install
- Run the example app:
cd example && npm install && npm run android
- Make your changes and test thoroughly
- Add tests for new features
- Update documentation as needed
- 🔍 Open an issue first for major changes to discuss the approach
- ✅ Include tests for new functionality
- 📝 Update documentation including TypeScript definitions
- 🧪 Test on multiple platforms (iOS and Android)
- 📱 Test with both architectures (old and new React Native architecture)
-
Follow existing TypeScript/JavaScript patterns
-
Use meaningful commit messages
-
Keep changes focused and atomic
-
To minimize playback delay, you may want to preload a sound file without calling
play()
(e.g.var s = new Sound(...);
) during app initialization. This also helps avoid a race condition whereplay()
may be called before loading of the sound is complete, which results in no sound but no error because loading is still being processed. -
You can play multiple sound files at the same time. Under the hood, this module uses
AVAudioSessionCategoryAmbient
to mix sounds on iOS. -
You may reuse a
Sound
instance for multiple playbacks. -
On iOS, the module wraps
AVAudioPlayer
that supports aac, aiff, mp3, wav etc. The full list of supported formats can be found at https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/SupportedAudioFormatsMacOSX/SupportedAudioFormatsMacOSX.html -
On Android, the module wraps
android.media.MediaPlayer
. The full list of supported formats can be found at https://developer.android.com/guide/topics/media/media-formats.html -
On Android, the absolute path can start with '/sdcard/'. So, if you want to access a sound called "my_sound.mp3" on Downloads folder, the absolute path will be: '/sdcard/Downloads/my_sound.mp3'.
-
You may chain non-getter calls, for example,
sound.setVolume(.5).setPan(.5).play()
.
MIT License - see LICENSE file for details.
If this library helps your project, consider:
- ⭐ Starring the repository
- 🐛 Reporting bugs and issues
- 📝 Contributing improvements
- 💬 Helping others in discussions
- 📢 Sharing with the community
Made with ❤️ by the React Native community