fix(mobile): migrate expo-av to expo-video and expo-audio

expo-av has no SDK 56 compatible release, and its EXEventEmitter.h
interface was removed from expo-modules-core, so the iOS release
archive fails compiling Pods/EXAV. Move video playback to
expo-video's useVideoPlayer/VideoView, and audio playback and
recording to expo-audio's createAudioPlayer/AudioModule.AudioRecorder,
preserving existing controls, mute/loop/resize behavior, and the
recording audio session configuration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jjbruntonandClaude Fable 5 committed 2026-08-31 14:35:51 +01:00
1 parent 5e28117662
commit b8cb2addff
11 files changed
+524 -387

No files matched your search

+59 -10
View File
@@ -113,17 +113,66 @@ jest.mock('expo-file-system/legacy', () => ({
},
}));
jest.mock('expo-av', () => ({
Audio: {
requestPermissionsAsync: jest.fn(async () => ({ status: 'granted' })),
setAudioModeAsync: jest.fn(async () => undefined),
Recording: {
createAsync: jest.fn(),
},
RecordingOptionsPresets: {
HIGH_QUALITY: {},
},
jest.mock('expo-video', () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const React = require('react');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { View } = require('react-native');
const createPlayer = () => ({
play: jest.fn(),
pause: jest.fn(),
replay: jest.fn(),
replace: jest.fn(),
replaceAsync: jest.fn(async () => undefined),
seekBy: jest.fn(),
addListener: jest.fn(() => ({ remove: jest.fn() })),
removeListener: jest.fn(),
playing: false,
muted: false,
loop: false,
currentTime: 0,
duration: 0,
status: 'idle',
});
return {
useVideoPlayer: jest.fn((source: unknown, setup?: (player: unknown) => void) => {
const player = createPlayer();
if (setup) setup(player);
return player;
}),
createVideoPlayer: jest.fn(() => createPlayer()),
VideoView: React.forwardRef((props: any, ref: any) =>
React.createElement(View, { ...props, ref })
),
};
});
jest.mock('expo-audio', () => ({
AudioModule: {
AudioRecorder: jest.fn(),
},
RecordingPresets: {
HIGH_QUALITY: {},
LOW_QUALITY: {},
},
requestRecordingPermissionsAsync: jest.fn(async () => ({ status: 'granted', granted: true })),
getRecordingPermissionsAsync: jest.fn(async () => ({ status: 'granted', granted: true })),
setAudioModeAsync: jest.fn(async () => undefined),
setIsAudioActiveAsync: jest.fn(async () => undefined),
useAudioPlayer: jest.fn(),
useAudioPlayerStatus: jest.fn(() => ({})),
createAudioPlayer: jest.fn(() => ({
play: jest.fn(),
pause: jest.fn(),
remove: jest.fn(),
seekTo: jest.fn(async () => undefined),
addListener: jest.fn(() => ({ remove: jest.fn() })),
currentTime: 0,
duration: 0,
playing: false,
})),
}));
jest.mock('react-native-compressor', () => ({