Skip to content

Commit 208820d

Browse files
committed
Fix adapters
1 parent 1824e07 commit 208820d

File tree

6 files changed

+158
-57
lines changed

6 files changed

+158
-57
lines changed

example/VideoLayerDemo.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ const styles = StyleSheet.create({
4949
flex: 1,
5050
backgroundColor: '#000',
5151
},
52-
});
52+
});

src/AdvancedVideo.tsx

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface AdvancedVideoProps {
1010
videoStyle?: StyleProp<ViewStyle>;
1111
enableAnalytics?: boolean;
1212
autoTrackAnalytics?: boolean;
13+
onPlaybackStatusUpdate?: (status: any) => void;
1314
analyticsOptions?: {
1415
customData?: any;
1516
videoPlayerType?: string;
@@ -120,6 +121,13 @@ class AdvancedVideo extends Component<AdvancedVideoProps, AdvancedVideoState> {
120121
};
121122

122123
private onPlaybackStatusUpdate = (status: any) => {
124+
console.log('AdvancedVideo - Status Update:', {
125+
adapterName: this.state.videoAdapter.getAdapterName(),
126+
videoUri: this.getVideoUri(),
127+
status: status,
128+
hasCallback: !!this.props.onPlaybackStatusUpdate
129+
});
130+
123131
if (this.props.enableAnalytics && this.videoRef.current && this.state.analyticsInitialized) {
124132
if (!this.videoRef.current._currentStatus) {
125133
this.videoRef.current._currentStatus = {};
@@ -136,11 +144,14 @@ class AdvancedVideo extends Component<AdvancedVideoProps, AdvancedVideoState> {
136144
}
137145
this.setState({ previousStatus: status });
138146
} catch (error) {
139-
// Silently fail if status processing fails
147+
console.log('AdvancedVideo - Status processing error:', error);
140148
}
141149
}
142150

143-
// Note: onPlaybackStatusUpdate forwarding removed as it's not in the interface anymore
151+
// Forward status updates to parent component
152+
if (this.props.onPlaybackStatusUpdate) {
153+
this.props.onPlaybackStatusUpdate(status);
154+
}
144155
};
145156

146157

@@ -234,8 +245,14 @@ class AdvancedVideo extends Component<AdvancedVideoProps, AdvancedVideoState> {
234245

235246
render() {
236247
const videoUri = this.getVideoUri();
248+
console.log('AdvancedVideo - Render:', {
249+
videoUri,
250+
adapterName: this.state.videoAdapter.getAdapterName(),
251+
isAdapterAvailable: this.state.videoAdapter.isAvailable()
252+
});
237253

238254
if (!videoUri) {
255+
console.log('AdvancedVideo - No video URI provided');
239256
return this.state.videoAdapter.renderVideo({
240257
videoUri: '',
241258
style: this.props.videoStyle,
@@ -247,13 +264,20 @@ class AdvancedVideo extends Component<AdvancedVideoProps, AdvancedVideoState> {
247264
videoUri,
248265
style: this.props.videoStyle,
249266
onPlaybackStatusUpdate: this.onPlaybackStatusUpdate,
250-
onLoadStart: () => {},
251-
onLoad: () => {},
252-
onError: (_error: any) => {},
267+
onLoadStart: () => {
268+
console.log('AdvancedVideo - Load Start');
269+
},
270+
onLoad: () => {
271+
console.log('AdvancedVideo - Load Complete');
272+
},
273+
onError: (error: any) => {
274+
console.log('AdvancedVideo - Load Error:', error);
275+
},
253276
}, this.videoRef);
254277

255278
return videoElement;
256279
} catch (error) {
280+
console.log('AdvancedVideo - Adapter Error:', error);
257281
// If the adapter fails, fall back to a fallback adapter
258282
const { FallbackVideoAdapter } = require('./adapters/FallbackVideoAdapter');
259283
const fallbackAdapter = new FallbackVideoAdapter(

src/adapters/ExpoAVVideoAdapter.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,45 @@ export class ExpoAVVideoAdapter implements VideoPlayerAdapter {
3333
throw new Error('expo-av is not available');
3434
}
3535

36+
console.log('ExpoAVVideoAdapter - Rendering video:', {
37+
videoUri: props.videoUri,
38+
hasOnPlaybackStatusUpdate: !!props.onPlaybackStatusUpdate
39+
});
40+
3641
const { Video } = this.expoAVModule;
3742

3843
return React.createElement(Video, {
3944
ref,
4045
source: { uri: props.videoUri },
4146
style: props.style,
42-
useNativeControls: true,
47+
useNativeControls: false,
4348
shouldPlay: false,
4449
isLooping: false,
4550
resizeMode: 'contain',
46-
onPlaybackStatusUpdate: props.onPlaybackStatusUpdate,
47-
onError: props.onError || (() => {}),
48-
onLoad: props.onLoad || (() => {}),
49-
onLoadStart: props.onLoadStart || (() => {}),
51+
onPlaybackStatusUpdate: (status: any) => {
52+
console.log('ExpoAVVideoAdapter - Status update:', status);
53+
if (props.onPlaybackStatusUpdate) {
54+
props.onPlaybackStatusUpdate(status);
55+
}
56+
},
57+
onError: (error: any) => {
58+
console.log('ExpoAVVideoAdapter - Error:', error);
59+
if (props.onError) {
60+
props.onError(error);
61+
}
62+
},
63+
onLoad: (data: any) => {
64+
console.log('ExpoAVVideoAdapter - Load:', data);
65+
if (props.onLoad) {
66+
props.onLoad(data);
67+
}
68+
},
69+
onLoadStart: (data: any) => {
70+
console.log('ExpoAVVideoAdapter - Load Start:', data);
71+
if (props.onLoadStart) {
72+
props.onLoadStart(data);
73+
}
74+
},
5075
});
5176
}
5277

src/adapters/ExpoVideoAdapter.tsx

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { VideoPlayerAdapter, VideoPlayerProps, VideoPlayerRef, VideoPlayerType }
44
export class ExpoVideoAdapter implements VideoPlayerAdapter {
55
private expoVideoModule: any = null;
66
private videoPlayer: any = null;
7+
private eventListeners: any[] = [];
78

89
constructor() {
910
this.loadExpoVideo();
@@ -35,49 +36,79 @@ export class ExpoVideoAdapter implements VideoPlayerAdapter {
3536
throw new Error('expo-video is not available');
3637
}
3738

39+
console.log('ExpoVideoAdapter - Rendering video:', {
40+
videoUri: props.videoUri,
41+
hasOnPlaybackStatusUpdate: !!props.onPlaybackStatusUpdate
42+
});
43+
3844
const { VideoView, createVideoPlayer } = this.expoVideoModule;
3945

4046
// Create or reuse the video player
4147
if (!this.videoPlayer) {
48+
console.log('ExpoVideoAdapter - Creating new video player');
4249
this.videoPlayer = createVideoPlayer(props.videoUri);
50+
51+
// Set up player event listeners for expo-video
52+
if (this.videoPlayer && props.onPlaybackStatusUpdate) {
53+
// Clear any existing listeners
54+
this.cleanup();
55+
56+
// Try different event names that might exist in expo-video
57+
const statusListener = this.videoPlayer.addListener?.('statusChange', (status: any) => {
58+
console.log('ExpoVideoAdapter - Player status change:', status);
59+
// Convert expo-video status to expo-av-like status format
60+
const normalizedStatus = {
61+
isLoaded: status.status === 'loaded' || status.status === 'readyToPlay',
62+
isPlaying: status.status === 'playing',
63+
positionMillis: (status.currentTime || 0) * 1000,
64+
durationMillis: (status.duration || 0) * 1000,
65+
isMuted: status.isMuted || false,
66+
error: status.error,
67+
...status
68+
};
69+
this.processExpoVideoEvents(ref.current, 'onPlaybackStatusUpdate', normalizedStatus);
70+
props.onPlaybackStatusUpdate?.(normalizedStatus);
71+
});
72+
73+
if (statusListener) {
74+
this.eventListeners.push(statusListener);
75+
}
76+
77+
// Try alternative event names
78+
const playbackListener = this.videoPlayer.addListener?.('playbackStatusUpdate', (status: any) => {
79+
console.log('ExpoVideoAdapter - Playback status update:', status);
80+
props.onPlaybackStatusUpdate?.(status);
81+
});
82+
83+
if (playbackListener) {
84+
this.eventListeners.push(playbackListener);
85+
}
86+
87+
// Simulate initial status for immediate feedback
88+
setTimeout(() => {
89+
const initialStatus = {
90+
isLoaded: false,
91+
isPlaying: false,
92+
positionMillis: 0,
93+
durationMillis: 0,
94+
isMuted: false,
95+
};
96+
console.log('ExpoVideoAdapter - Sending initial status');
97+
props.onPlaybackStatusUpdate?.(initialStatus);
98+
}, 100);
99+
}
43100
} else {
44101
// Update the source if it changed
102+
console.log('ExpoVideoAdapter - Updating video source');
45103
this.videoPlayer.source = props.videoUri;
46104
}
47105

48106
return React.createElement(VideoView, {
49107
ref,
50108
player: this.videoPlayer,
51109
style: props.style,
52-
nativeControls: true,
53-
onPlaybackStatusUpdate: (status: any) => {
54-
this.processExpoVideoEvents(ref.current, 'onPlaybackStatusUpdate', status);
55-
props.onPlaybackStatusUpdate?.(status);
56-
},
57-
onLoadStart: (data: any) => {
58-
this.processExpoVideoEvents(ref.current, 'onLoadStart', data);
59-
props.onLoadStart?.(data);
60-
},
61-
onLoad: (data: any) => {
62-
this.processExpoVideoEvents(ref.current, 'onLoad', data);
63-
props.onLoad?.(data);
64-
},
65-
onError: (error: any) => {
66-
this.processExpoVideoEvents(ref.current, 'onError', error);
67-
props.onError?.(error);
68-
},
69-
onReadyForDisplay: (data: any) => {
70-
this.processExpoVideoEvents(ref.current, 'onReadyForDisplay', data);
71-
props.onReadyForDisplay?.(data);
72-
},
73-
onPlayingChange: (isPlaying: boolean) => {
74-
this.processExpoVideoEvents(ref.current, 'onPlayingChange', isPlaying);
75-
props.onPlayingChange?.(isPlaying);
76-
},
77-
onEnd: (data: any) => {
78-
this.processExpoVideoEvents(ref.current, 'onEnd', data);
79-
props.onEnd?.(data);
80-
},
110+
nativeControls: false,
111+
// Note: expo-video uses player event listeners instead of VideoView props for status updates
81112
});
82113
}
83114

@@ -110,6 +141,13 @@ export class ExpoVideoAdapter implements VideoPlayerAdapter {
110141
}
111142

112143
cleanup(): void {
144+
// Remove all event listeners
145+
this.eventListeners.forEach(listener => {
146+
if (listener && typeof listener.remove === 'function') {
147+
listener.remove();
148+
}
149+
});
150+
this.eventListeners = [];
113151
this.videoPlayer = null;
114152
}
115153
}

src/adapters/VideoPlayerFactory.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ export class VideoPlayerFactory {
1414
if (this.initialized) return;
1515

1616
this.adapters = [
17-
new ExpoVideoAdapter(), // Try expo-video first (newer package)
18-
new ExpoAVVideoAdapter(), // Fallback to expo-av
17+
new ExpoAVVideoAdapter(), // Try expo-av first (more stable for this use case)
18+
new ExpoVideoAdapter(), // Fallback to expo-video
1919
];
2020

2121
this.initialized = true;
@@ -27,17 +27,21 @@ export class VideoPlayerFactory {
2727
static getAvailableAdapter(): VideoPlayerAdapter {
2828
this.initializeAdapters();
2929

30+
console.log('VideoPlayerFactory - Checking adapters...');
3031
// Find the first available adapter
3132
for (const adapter of this.adapters) {
3233
const adapterName = adapter.getAdapterName();
3334
const isAvailable = adapter.isAvailable();
35+
console.log(`VideoPlayerFactory - ${adapterName}: ${isAvailable ? 'Available' : 'Not Available'}`);
3436

3537
if (isAvailable) {
38+
console.log(`VideoPlayerFactory - Using adapter: ${adapterName}`);
3639
return adapter;
3740
}
3841
}
3942

4043
// If no adapter is available, return fallback
44+
console.log('VideoPlayerFactory - No adapters available, using fallback');
4145
return new FallbackVideoAdapter('No video player library found. Install expo-video or expo-av.');
4246
}
4347

src/widgets/video/layer/CLDVideoLayer.tsx

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -234,23 +234,32 @@ export class CLDVideoLayer extends React.Component<CLDVideoLayerProps, CLDVideoL
234234
};
235235

236236
handleStatusUpdate = (s: any) => {
237-
if (s.isLoaded) {
238-
if (this.state.isSeekingComplete && this.state.lastSeekPosition > 0) {
239-
const currentVideoPosition = s.positionMillis || 0;
240-
const seekPositionDiff = Math.abs(currentVideoPosition - this.state.lastSeekPosition);
241-
242-
if (seekPositionDiff < 500) {
243-
this.setState({
244-
status: s,
245-
isSeekingComplete: false,
246-
lastSeekPosition: 0
247-
});
248-
return;
249-
}
250-
}
237+
console.log('CLDVideoLayer - Status Update:', {
238+
isLoaded: s?.isLoaded,
239+
durationMillis: s?.durationMillis,
240+
positionMillis: s?.positionMillis,
241+
isPlaying: s?.isPlaying,
242+
error: s?.error,
243+
hasFullStatus: !!s,
244+
currentVideoLoaded: this.state.status?.isLoaded
245+
});
246+
247+
// Always update status to handle loading states properly
248+
if (this.state.isSeekingComplete && this.state.lastSeekPosition > 0 && s?.isLoaded) {
249+
const currentVideoPosition = s.positionMillis || 0;
250+
const seekPositionDiff = Math.abs(currentVideoPosition - this.state.lastSeekPosition);
251251

252-
this.setState({ status: s });
252+
if (seekPositionDiff < 500) {
253+
this.setState({
254+
status: s,
255+
isSeekingComplete: false,
256+
lastSeekPosition: 0
257+
});
258+
return;
259+
}
253260
}
261+
262+
this.setState({ status: s });
254263
};
255264

256265
handlePlayPause = async () => {
@@ -306,6 +315,7 @@ export class CLDVideoLayer extends React.Component<CLDVideoLayerProps, CLDVideoL
306315
cldVideo={cldVideo}
307316
videoUrl={videoUrl}
308317
videoStyle={StyleSheet.absoluteFill}
318+
onPlaybackStatusUpdate={this.handleStatusUpdate}
309319
/>
310320

311321
{/* Loading Spinner */}

0 commit comments

Comments
 (0)