React Native course · Module 6: Photos, camera and audio
expo-av - Audio and Video
In this lesson5
Play audio and video in your application!
Installation
npx expo install expo-avVideo Playback
import { Video, ResizeMode } from 'expo-av';
import { useState, useRef } from 'react';
function VideoPlayer() {
const videoRef = useRef<Video>(null);
const [status, setStatus] = useState<any>({});
return (
<View style={styles.container}>
<Video
ref={videoRef}
style={styles.video}
source={{ uri: 'https://example.com/video.mp4' }}
useNativeControls
resizeMode={ResizeMode.CONTAIN}
isLooping
onPlaybackStatusUpdate={(status) => setStatus(() => status)}
/>
<View style={styles.controls}>
<Pressable
onPress={() =>
status.isPlaying
? videoRef.current?.pauseAsync()
: videoRef.current?.playAsync()
}
>
<Ionicons
name={status.isPlaying ? 'pause' : 'play'}
size={32}
/>
</Pressable>
</View>
</View>
);
}Audio Playback
import { Audio } from 'expo-av';
function AudioPlayer() {
const [sound, setSound] = useState<Audio.Sound>();
const [isPlaying, setIsPlaying] = useState(false);
const playSound = async () => {
const { sound } = await Audio.Sound.createAsync(
require('@/assets/audio/ocean.mp3')
);
setSound(sound);
await sound.playAsync();
setIsPlaying(true);
};
const pauseSound = async () => {
if (sound) {
await sound.pauseAsync();
setIsPlaying(false);
}
};
// Cleanup
useEffect(() => {
return sound
? () => {
sound.unloadAsync();
}
: undefined;
}, [sound]);
return (
<Pressable onPress={isPlaying ? pauseSound : playSound}>
<Ionicons name={isPlaying ? 'pause' : 'play'} size={48} />
</Pressable>
);
}Background Audio
import { Audio } from 'expo-av';
async function setupAudio() {
await Audio.setAudioModeAsync({
playsInSilentModeIOS: true,
staysActiveInBackground: true,
shouldDuckAndroid: true,
});
}Audio Recording
import { Audio } from 'expo-av';
function AudioRecorder() {
const [recording, setRecording] = useState<Audio.Recording>();
const [recordingUri, setRecordingUri] = useState<string>();
const startRecording = async () => {
try {
const permission = await Audio.requestPermissionsAsync();
if (!permission.granted) return;
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
});
const { recording } = await Audio.Recording.createAsync(
Audio.RecordingOptionsPresets.HIGH_QUALITY
);
setRecording(recording);
} catch (error) {
console.error('Recording error:', error);
}
};
const stopRecording = async () => {
if (!recording) return;
await recording.stopAndUnloadAsync();
const uri = recording.getURI();
setRecordingUri(uri ?? undefined);
setRecording(undefined);
};
return (
<View>
<Pressable
onPress={recording ? stopRecording : startRecording}
style={[styles.recordButton, recording && styles.recording]}
>
<Ionicons name={recording ? 'stop' : 'mic'} size={32} color="white" />
</Pressable>
{recordingUri && <Text>Recorded: {recordingUri}</Text>}
</View>
);
}expo-av handles all your audio/video needs!
Code for this lesson: App.tsx
import React, { useState, useEffect } from 'react';
import { View, Text, Pressable, StyleSheet } from 'react-native';
import { Audio } from 'expo-av';
export default function App() {
const [sound, setSound] = useState<Audio.Sound>();
const [isPlaying, setIsPlaying] = useState(false);
const playSound = async () => {
// TODO: create a sound using Audio.Sound.createAsync(...)
// - pass { uri: 'https://example.com/ocean.mp3' } as the source
// - destructure the result: const { sound } = await Audio.Sound.createAsync(...)
// - store it: setSound(sound)
// - start playback: await sound.playAsync()
// - set setIsPlaying(true)
};
const pauseSound = async () => {
if (sound) {
await sound.pauseAsync();
setIsPlaying(false);
}
};
// Release the sound resource on unmount
useEffect(() => {
return sound ? () => { sound.unloadAsync(); } : undefined;
}, [sound]);
return (
<View style={styles.container}>
<Text style={styles.title}>Sounds of Atlantis</Text>
<Pressable
style={styles.button}
onPress={isPlaying ? pauseSound : playSound}
>
<Text style={styles.buttonText}>{isPlaying ? 'Pause' : 'Play'}</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#1a5276' },
title: { color: '#aed6f1', fontSize: 20, marginBottom: 24 },
button: { backgroundColor: '#2980b9', paddingVertical: 14, paddingHorizontal: 40, borderRadius: 8 },
buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' },
});Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. Which prop enables native controls in the Video component?
Hands-on tasks in the game
- Click in order
Click the elements for creating a sound:
- Code editor
Complete the Audio.Sound code with play/pause.