fix TEST CP

This commit is contained in:
tapframe 2025-09-17 03:02:31 +05:30
parent 1ee1a0c3f7
commit f44c0df168
2 changed files with 152 additions and 56 deletions

View file

@ -973,29 +973,39 @@ const AndroidVideoPlayer: React.FC = () => {
if (selectedAudioTrack === -1 && rnVideoAudioTracks.length > 1) { if (selectedAudioTrack === -1 && rnVideoAudioTracks.length > 1) {
logger.warn('[AndroidVideoPlayer] Detected disabled audio track, attempting fallback'); logger.warn('[AndroidVideoPlayer] Detected disabled audio track, attempting fallback');
// Find a fallback audio track (prefer stereo/standard formats) // Find a fallback audio track (prioritize AAC/stereo over heavy codecs)
const fallbackTrack = rnVideoAudioTracks.find((track, index) => { const fallbackTrack = rnVideoAudioTracks.find((track) => {
const trackName = (track.name || '').toLowerCase();
// Prefer AAC, stereo, or standard audio formats, avoid heavy codecs
const isCompatible = !trackName.includes('truehd') &&
!trackName.includes('dts') &&
!trackName.includes('atmos') &&
track.id !== selectedAudioTrack; // Don't select the same track
// Prioritize AAC and stereo tracks
const isPreferred = trackName.includes('aac') ||
trackName.includes('stereo') ||
trackName.includes('2.0') ||
trackName.includes('2ch');
return isCompatible && isPreferred;
}) || rnVideoAudioTracks.find((track) => {
// Fallback: any compatible track (even if not preferred)
const trackName = (track.name || '').toLowerCase(); const trackName = (track.name || '').toLowerCase();
const trackLang = (track.language || '').toLowerCase();
// Prefer stereo, AAC, or standard audio formats, avoid heavy codecs
return !trackName.includes('truehd') && return !trackName.includes('truehd') &&
!trackName.includes('dts') && !trackName.includes('dts') &&
!trackName.includes('dolby') &&
!trackName.includes('atmos') && !trackName.includes('atmos') &&
!trackName.includes('7.1') && track.id !== selectedAudioTrack;
!trackName.includes('5.1') &&
index !== selectedAudioTrack; // Don't select the same track
}); });
if (fallbackTrack) { if (fallbackTrack) {
const fallbackIndex = rnVideoAudioTracks.indexOf(fallbackTrack); logger.warn(`[AndroidVideoPlayer] Switching to fallback audio track: ${fallbackTrack.name || 'Unknown'} (id: ${fallbackTrack.id})`);
logger.warn(`[AndroidVideoPlayer] Switching to fallback audio track: ${fallbackTrack.name || 'Unknown'} (index: ${fallbackIndex})`);
// Increment fallback attempts counter // Increment fallback attempts counter
setAudioTrackFallbackAttempts(prev => prev + 1); setAudioTrackFallbackAttempts(prev => prev + 1);
// Switch to fallback audio track // Switch to fallback audio track
setSelectedAudioTrack(fallbackIndex); setSelectedAudioTrack(fallbackTrack.id);
// Brief pause to allow track switching // Brief pause to allow track switching
setPaused(true); setPaused(true);
@ -1189,23 +1199,39 @@ const AndroidVideoPlayer: React.FC = () => {
}); });
setRnVideoAudioTracks(formattedAudioTracks); setRnVideoAudioTracks(formattedAudioTracks);
// Auto-select English audio track if available, otherwise first track // Auto-select compatible audio track (prioritize AAC/stereo over heavy codecs)
if (selectedAudioTrack === null && formattedAudioTracks.length > 0) { if (selectedAudioTrack === null && formattedAudioTracks.length > 0) {
// Look for English track first // First, try to find a compatible English track
const englishTrack = formattedAudioTracks.find((track: {id: number, name: string, language?: string}) => { const compatibleEnglishTrack = formattedAudioTracks.find((track: {id: number, name: string, language?: string}) => {
const lang = (track.language || '').toLowerCase(); const lang = (track.language || '').toLowerCase();
return lang === 'english' || lang === 'en' || lang === 'eng' || const trackName = (track.name || '').toLowerCase();
(track.name && track.name.toLowerCase().includes('english')); const isEnglish = lang === 'english' || lang === 'en' || lang === 'eng' ||
(track.name && track.name.toLowerCase().includes('english'));
const isCompatible = !trackName.includes('truehd') &&
!trackName.includes('dts') &&
!trackName.includes('atmos');
return isEnglish && isCompatible;
}); });
const selectedTrack = englishTrack || formattedAudioTracks[0]; // If no compatible English track, find any compatible track
const compatibleTrack = compatibleEnglishTrack || formattedAudioTracks.find((track: {id: number, name: string, language?: string}) => {
const trackName = (track.name || '').toLowerCase();
return !trackName.includes('truehd') &&
!trackName.includes('dts') &&
!trackName.includes('atmos');
});
// Fallback to any track if no compatible ones found
const selectedTrack = compatibleTrack || formattedAudioTracks[0];
setSelectedAudioTrack(selectedTrack.id); setSelectedAudioTrack(selectedTrack.id);
if (DEBUG_MODE) { if (DEBUG_MODE) {
if (englishTrack) { if (compatibleEnglishTrack) {
logger.log(`[AndroidVideoPlayer] Auto-selected English audio track: ${selectedTrack.name} (ID: ${selectedTrack.id})`); logger.log(`[AndroidVideoPlayer] Auto-selected compatible English audio track: ${selectedTrack.name} (ID: ${selectedTrack.id})`);
} else if (compatibleTrack) {
logger.log(`[AndroidVideoPlayer] Auto-selected compatible audio track: ${selectedTrack.name} (ID: ${selectedTrack.id})`);
} else { } else {
logger.log(`[AndroidVideoPlayer] No English track found, auto-selected first audio track: ${selectedTrack.name} (ID: ${selectedTrack.id})`); logger.log(`[AndroidVideoPlayer] No compatible tracks found, auto-selected first audio track: ${selectedTrack.name} (ID: ${selectedTrack.id})`);
} }
} }
} }
@ -1440,31 +1466,41 @@ const AndroidVideoPlayer: React.FC = () => {
error.error.errorException.includes('audio/eac3')) || error.error.errorException.includes('audio/eac3')) ||
(error?.error?.errorException && (error?.error?.errorException &&
error.error.errorException.includes('Dolby Digital Plus')) || error.error.errorException.includes('Dolby Digital Plus')) ||
(error?.message && /(trhd|truehd|true\s?hd|dts|dolby|atmos|e-ac3|ac3)/i.test(error.message)) || (error?.message && /(trhd|truehd|true\s?hd|dts|atmos)/i.test(error.message)) ||
(error?.error?.message && /(trhd|truehd|true\s?hd|dts|dolby|atmos|e-ac3|ac3)/i.test(error.error.message)) || (error?.error?.message && /(trhd|truehd|true\s?hd|dts|atmos)/i.test(error.error.message)) ||
(error?.title && /codec not supported/i.test(error.title)); (error?.title && /codec not supported/i.test(error.title));
// Handle audio codec errors with automatic fallback // Handle audio codec errors with automatic fallback
if (isAudioCodecError && rnVideoAudioTracks.length > 1) { if (isAudioCodecError && rnVideoAudioTracks.length > 0) {
logger.warn('[AndroidVideoPlayer] Audio codec error detected, attempting audio track fallback'); logger.warn('[AndroidVideoPlayer] Audio codec error detected, attempting audio track fallback');
// Find a fallback audio track (prefer stereo/standard formats) // Find a fallback audio track (prioritize AAC/stereo over heavy codecs)
const fallbackTrack = rnVideoAudioTracks.find((track, index) => { const fallbackTrack = rnVideoAudioTracks.find((track) => {
const trackName = (track.name || '').toLowerCase();
// Prefer AAC, stereo, or standard audio formats, avoid heavy codecs
const isCompatible = !trackName.includes('truehd') &&
!trackName.includes('dts') &&
!trackName.includes('atmos') &&
track.id !== selectedAudioTrack; // Don't select the same track
// Prioritize AAC and stereo tracks
const isPreferred = trackName.includes('aac') ||
trackName.includes('stereo') ||
trackName.includes('2.0') ||
trackName.includes('2ch');
return isCompatible && isPreferred;
}) || rnVideoAudioTracks.find((track) => {
// Fallback: any compatible track (even if not preferred)
const trackName = (track.name || '').toLowerCase(); const trackName = (track.name || '').toLowerCase();
const trackLang = (track.language || '').toLowerCase();
// Prefer stereo, AAC, or standard audio formats, avoid heavy codecs
return !trackName.includes('truehd') && return !trackName.includes('truehd') &&
!trackName.includes('dts') && !trackName.includes('dts') &&
!trackName.includes('dolby') &&
!trackName.includes('atmos') && !trackName.includes('atmos') &&
!trackName.includes('7.1') && track.id !== selectedAudioTrack;
!trackName.includes('5.1') &&
index !== selectedAudioTrack; // Don't select the same track
}); });
if (fallbackTrack) { if (fallbackTrack) {
const fallbackIndex = rnVideoAudioTracks.indexOf(fallbackTrack); logger.warn(`[AndroidVideoPlayer] Switching to fallback audio track: ${fallbackTrack.name || 'Unknown'} (id: ${fallbackTrack.id})`);
logger.warn(`[AndroidVideoPlayer] Switching to fallback audio track: ${fallbackTrack.name || 'Unknown'} (index: ${fallbackIndex})`);
// Clear any existing error state // Clear any existing error state
if (errorTimeoutRef.current) { if (errorTimeoutRef.current) {
@ -1474,7 +1510,7 @@ const AndroidVideoPlayer: React.FC = () => {
safeSetState(() => setShowErrorModal(false)); safeSetState(() => setShowErrorModal(false));
// Switch to fallback audio track // Switch to fallback audio track
setSelectedAudioTrack(fallbackIndex); setSelectedAudioTrack(fallbackTrack.id);
// Brief pause to allow track switching // Brief pause to allow track switching
setPaused(true); setPaused(true);
@ -1484,6 +1520,21 @@ const AndroidVideoPlayer: React.FC = () => {
}, 500); }, 500);
return; // Don't show error UI, attempt recovery return; // Don't show error UI, attempt recovery
} else {
// As a last resort, disable audio entirely to keep video playing
logger.warn('[AndroidVideoPlayer] No compatible audio track found. Disabling audio to keep playback.');
if (errorTimeoutRef.current) {
clearTimeout(errorTimeoutRef.current);
errorTimeoutRef.current = null;
}
safeSetState(() => setShowErrorModal(false));
setSelectedAudioTrack(-1); // handled as DISABLED by selectedTextTrack prop
setPaused(true);
setTimeout(() => {
if (!isMounted.current) return;
setPaused(false);
}, 300);
return;
} }
} }
@ -1631,23 +1682,30 @@ const AndroidVideoPlayer: React.FC = () => {
} }
} }
// Use safeSetState to prevent crashes on iOS when component is unmounted // For audio codec errors we already attempted recovery; avoid showing the modal
safeSetState(() => { if (!isAudioCodecError) {
setErrorDetails(errorMessage); // Use safeSetState to prevent crashes on iOS when component is unmounted
setShowErrorModal(true); safeSetState(() => {
}); setErrorDetails(errorMessage);
setShowErrorModal(true);
});
} else {
return;
}
// Clear any existing timeout // Clear any existing timeout
if (errorTimeoutRef.current) { if (errorTimeoutRef.current) {
clearTimeout(errorTimeoutRef.current); clearTimeout(errorTimeoutRef.current);
} }
// Auto-exit after 5 seconds if user doesn't dismiss // Auto-exit only when a modal is actually visible
errorTimeoutRef.current = setTimeout(() => { if (showErrorModal) {
if (isMounted.current) { errorTimeoutRef.current = setTimeout(() => {
handleErrorExit(); if (isMounted.current) {
} handleErrorExit();
}, 5000); }
}, 5000);
}
} catch (handlerError) { } catch (handlerError) {
// Fallback error handling to prevent crashes during error processing // Fallback error handling to prevent crashes during error processing
logger.error('[AndroidVideoPlayer] Error in error handler:', handlerError); logger.error('[AndroidVideoPlayer] Error in error handler:', handlerError);

View file

@ -149,6 +149,13 @@ export const AudioTrackModal: React.FC<AudioTrackModalProps> = ({
// If no track is selected, show the first track as selected // If no track is selected, show the first track as selected
const isSelected = selectedAudioTrack === track.id || const isSelected = selectedAudioTrack === track.id ||
(selectedAudioTrack === null && track.id === vlcAudioTracks[0]?.id); (selectedAudioTrack === null && track.id === vlcAudioTracks[0]?.id);
// Check if track uses unsupported codec
const trackName = (track.name || '').toLowerCase();
const isUnsupported = trackName.includes('truehd') ||
trackName.includes('dts') ||
trackName.includes('atmos');
return ( return (
<TouchableOpacity <TouchableOpacity
key={track.id} key={track.id}
@ -158,8 +165,15 @@ export const AudioTrackModal: React.FC<AudioTrackModalProps> = ({
padding: 16, padding: 16,
borderWidth: 1, borderWidth: 1,
borderColor: isSelected ? 'rgba(34, 197, 94, 0.3)' : 'rgba(255, 255, 255, 0.1)', borderColor: isSelected ? 'rgba(34, 197, 94, 0.3)' : 'rgba(255, 255, 255, 0.1)',
opacity: isUnsupported ? 0.5 : 1,
}} }}
onPress={() => { onPress={() => {
if (isUnsupported) {
if (DEBUG_MODE) {
logger.log(`[AudioTrackModal] Attempted to select unsupported track: ${track.id} (${track.name})`);
}
return; // Don't allow selection of unsupported tracks
}
if (DEBUG_MODE) { if (DEBUG_MODE) {
logger.log(`[AudioTrackModal] Selecting track: ${track.id} (${track.name})`); logger.log(`[AudioTrackModal] Selecting track: ${track.id} (${track.name})`);
} }
@ -169,30 +183,54 @@ export const AudioTrackModal: React.FC<AudioTrackModalProps> = ({
setShowAudioModal(false); setShowAudioModal(false);
}, 200); }, 200);
}} }}
activeOpacity={0.7} activeOpacity={isUnsupported ? 1 : 0.7}
> >
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}> <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
<View style={{ flex: 1 }}> <View style={{ flex: 1 }}>
<Text style={{ <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 4 }}>
color: '#FFFFFF', <Text style={{
fontSize: 15, color: isUnsupported ? 'rgba(255, 255, 255, 0.4)' : '#FFFFFF',
fontWeight: '500', fontSize: 15,
marginBottom: 4, fontWeight: '500',
}}> flex: 1,
{getTrackDisplayName(track)} }}>
</Text> {getTrackDisplayName(track)}
</Text>
{isUnsupported && (
<View style={{
backgroundColor: 'rgba(255, 107, 107, 0.2)',
borderRadius: 8,
paddingHorizontal: 8,
paddingVertical: 2,
marginLeft: 8,
}}>
<Text style={{
color: '#FF6B6B',
fontSize: 10,
fontWeight: '600',
textTransform: 'uppercase',
letterSpacing: 0.5,
}}>
Unsupported
</Text>
</View>
)}
</View>
{track.language && ( {track.language && (
<Text style={{ <Text style={{
color: 'rgba(255, 255, 255, 0.6)', color: isUnsupported ? 'rgba(255, 255, 255, 0.3)' : 'rgba(255, 255, 255, 0.6)',
fontSize: 13, fontSize: 13,
}}> }}>
{track.language.toUpperCase()} {track.language.toUpperCase()}
</Text> </Text>
)} )}
</View> </View>
{isSelected && ( {isSelected && !isUnsupported && (
<MaterialIcons name="check" size={20} color="#22C55E" /> <MaterialIcons name="check" size={20} color="#22C55E" />
)} )}
{isSelected && isUnsupported && (
<MaterialIcons name="warning" size={20} color="#FF6B6B" />
)}
</View> </View>
</TouchableOpacity> </TouchableOpacity>
); );