mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 13:39:41 +02:00
Move inactive projects out of active workspace: - bauntown (community website) - maerchenzauber (AI story generation) - memoro (voice memo app) - news (news aggregation) - nutriphi (nutrition tracking) - reader (reading app) - uload (URL shortener) - wisekeep (AI wisdom extraction) Update CLAUDE.md documentation: - Add presi to active projects - Document archived projects section - Update workspace configuration Archived apps can be re-activated by moving back to apps/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
7.4 KiB
7.4 KiB
expo-av to expo-audio Migration Guide
Overview
This guide documents the migration from expo-av to expo-audio completed as part of the Expo SDK 54 upgrade to address Android 16 compatibility issues and deprecation warnings.
Background
Why We Migrated
- Deprecation:
expo-avwas deprecated in Expo SDK 54 - Android 16 Issues: Recording functionality broken on Android 16 devices
- Performance:
expo-audiooffers better performance and smaller bundle size - Future Support:
expo-audiois actively maintained and developed
Timeline
- Date: January 2025
- Expo SDK: 53 → 54
- React Native: 0.79.2 → 0.81.4
- expo-av: 15.1.4 → removed
- expo-audio: not used → 1.0.13
Migration Steps
1. Package Installation
# Remove expo-av
npm uninstall expo-av
# Install expo-audio
npm install expo-audio@~1.0.13
# Clean and reinstall
npx expo install --fix
2. Import Changes
Recording
// Before (expo-av)
import { Audio } from 'expo-av';
// After (expo-audio)
import {
AudioRecorder,
RecordingPresets,
setAudioModeAsync,
requestRecordingPermissionsAsync,
getRecordingPermissionsAsync,
} from 'expo-audio';
Playback
// Before (expo-av)
import { Audio } from 'expo-av';
// After (expo-audio)
import { AudioPlayer, createAudioPlayer, setAudioModeAsync } from 'expo-audio';
3. API Changes
Recording API
Starting Recording
// Before (expo-av)
const recording = new Audio.Recording();
await recording.prepareToRecordAsync(Audio.RecordingOptionsPresets.HIGH_QUALITY);
await recording.startAsync();
// After (expo-audio)
const recorder = new AudioRecorder(RecordingPresets.HIGH_QUALITY);
await recorder.prepareToRecordAsync();
recorder.record(); // Note: synchronous, not async
Stopping Recording
// Before (expo-av)
await recording.stopAndUnloadAsync();
const uri = recording.getURI();
// After (expo-audio)
await recorder.stop();
const uri = recorder.uri; // Direct property access
Pause/Resume
// Before (expo-av)
await recording.pauseAsync();
await recording.startAsync(); // Resume
// After (expo-audio)
recorder.pause(); // Synchronous
recorder.record(); // Resume (same as start)
Playback API
Creating Player
// Before (expo-av)
const { sound } = await Audio.Sound.createAsync({ uri }, { progressUpdateIntervalMillis: 100 });
// After (expo-audio)
const player = createAudioPlayer(uri);
// Note: No progress update interval option; use polling
Playback Control
// Before (expo-av)
await sound.playAsync();
await sound.pauseAsync();
await sound.stopAsync();
await sound.setPositionAsync(positionMillis);
await sound.unloadAsync();
// After (expo-audio)
await player.play();
await player.pause();
await player.stop();
player.currentTime = positionSeconds; // Note: seconds, not milliseconds
player.release(); // Synchronous cleanup
Status Updates
// Before (expo-av)
sound.setOnPlaybackStatusUpdate((status) => {
if (status.isLoaded) {
console.log(status.positionMillis, status.durationMillis);
}
});
// After (expo-audio)
// No built-in status updates; use polling
setInterval(() => {
console.log(player.currentTime, player.duration); // In seconds
console.log(player.playing); // Boolean
}, 100);
Audio Mode Configuration
// Before (expo-av)
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
staysActiveInBackground: true,
interruptionModeIOS: InterruptionModeIOS.DoNotMix,
interruptionModeAndroid: InterruptionModeAndroid.DoNotMix,
shouldDuckAndroid: true,
playThroughEarpieceAndroid: false,
});
// After (expo-audio)
await setAudioModeAsync({
allowsRecording: true,
playsInSilentMode: true,
shouldPlayInBackground: true,
interruptionMode: 'doNotMix', // String literals instead of enums
// Note: Some options like shouldDuckAndroid are not available
});
Permissions
// Before (expo-av)
const { status } = await Audio.requestPermissionsAsync();
const { status } = await Audio.getPermissionsAsync();
// After (expo-audio)
const { granted } = await requestRecordingPermissionsAsync();
const { granted } = await getRecordingPermissionsAsync();
Files Modified
Core Recording Services
features/audioRecording/audioRecording.service.tsfeatures/audioRecording/audioRecording.service.android.tsfeatures/audioRecording/audioRecording.service.ios.tsfeatures/audioRecording/audioRecording.service.web.tsfeatures/audioRecording/audioRecording.types.ts
Audio Player
features/audioPlayer/useAudioPlayer.tsfeatures/audioPlayer/store/audioPlaybackStore.ts
Storage & Utilities
features/storage/fileStorage.service.tsfeatures/storage/fileStorage.service.web.tsutils/mediaUtils.ts
Sound Effects
features/audioRecording/services/recordingSoundManager.ts
Configuration
package.jsonapp.json(plugin configuration)
Platform-Specific Considerations
Android 16
- Added foreground state verification before recording
- Implemented AppState monitoring for background restrictions
- Added explicit error handling for permission denials
iOS
- Maintained compatibility with existing iOS audio session configuration
- No significant changes required for iOS implementation
Web
- Updated to use Web Audio API compatible methods
- Maintained fallback for permissions API
Known Issues & Workarounds
1. Zero-byte Audio Files (Expo SDK 54)
Issue: Some Android devices create zero-byte audio files Reference: GitHub issue #39646 Workaround: Added logging and validation after recording stops
2. Missing Status Updates
Issue: No built-in playback status updates like expo-av Solution: Implemented polling mechanism with setInterval
3. Time Units Difference
Issue: expo-audio uses seconds, expo-av used milliseconds Solution: Added conversion where necessary (÷ 1000 for ms → s)
Benefits Achieved
- Android 16 Compatibility: Recording works on latest Android devices
- Smaller Bundle: Reduced app size by ~200KB
- Better Performance: Faster audio initialization and lower memory usage
- Simpler API: More intuitive method names and patterns
- Future-Proof: Active development and support from Expo team
Testing Checklist
- Audio recording starts successfully
- Recording can be paused and resumed
- Recording stops and saves properly
- Audio playback works correctly
- Seek/scrub functionality works
- Volume controls function properly
- Background recording (iOS)
- Permissions are requested correctly
- Sound effects play correctly
- Multiple audio instances don't conflict
Rollback Plan
If issues arise, rollback by:
- Revert package.json changes
- Run
npm install expo-av@~15.1.4 - Revert all file changes listed above
- Run
npx expo install --fix - Clean build folders and rebuild
Resources
Contact
For questions about this migration, please refer to the project maintainers or create an issue in the project repository.