Fix Android speaker: use music stream type instead of voiceCall
- audioStreamType: music (routes to SPEAKER by default) - audioMode: normal (not inCommunication which uses earpiece) - audioAttributesUsageType: media - audioAttributesContentType: music Previous voiceCall stream was routing to earpiece on Android devices.
This commit is contained in:
parent
8240e51bc5
commit
cd4137ef36
@ -93,50 +93,32 @@ export async function configureAudioForVoiceCall(): Promise<void> {
|
|||||||
}
|
}
|
||||||
} else if (Platform.OS === 'android') {
|
} else if (Platform.OS === 'android') {
|
||||||
// Android-specific configuration - FORCE SPEAKER OUTPUT
|
// Android-specific configuration - FORCE SPEAKER OUTPUT
|
||||||
// SOLUTION: Use 'inCommunication' for echo cancellation + forceHandleAudioRouting + explicit speaker selection
|
// CRITICAL: Use 'music' stream type - it defaults to SPEAKER!
|
||||||
console.log('[AudioSession] Configuring Android audio for SPEAKER with echo cancellation...');
|
// 'voiceCall' stream type defaults to EARPIECE on many Android devices
|
||||||
|
console.log('[AudioSession] Configuring Android audio for SPEAKER...');
|
||||||
|
|
||||||
await AudioSession.configureAudio({
|
await AudioSession.configureAudio({
|
||||||
android: {
|
android: {
|
||||||
// Force speaker as preferred output
|
// Use MEDIA mode to ensure speaker output
|
||||||
preferredOutputList: ['speaker'],
|
|
||||||
// CRITICAL: This flag forces audio routing even in communication mode
|
|
||||||
forceHandleAudioRouting: true,
|
|
||||||
audioTypeOptions: {
|
audioTypeOptions: {
|
||||||
manageAudioFocus: true,
|
manageAudioFocus: true,
|
||||||
// Use 'inCommunication' for echo cancellation (important for voice calls!)
|
audioMode: 'normal',
|
||||||
audioMode: 'inCommunication',
|
|
||||||
audioFocusMode: 'gain',
|
audioFocusMode: 'gain',
|
||||||
// Voice call stream type for proper routing
|
// Use 'music' stream - goes to speaker by default!
|
||||||
audioStreamType: 'voiceCall',
|
audioStreamType: 'music',
|
||||||
audioAttributesUsageType: 'voiceCommunication',
|
audioAttributesUsageType: 'media',
|
||||||
audioAttributesContentType: 'speech',
|
audioAttributesContentType: 'music',
|
||||||
},
|
},
|
||||||
|
// Force speaker as output
|
||||||
|
preferredOutputList: ['speaker'],
|
||||||
|
// Allow us to control audio routing
|
||||||
|
forceHandleAudioRouting: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('[AudioSession] Starting Android audio session...');
|
console.log('[AudioSession] Starting Android audio session...');
|
||||||
await AudioSession.startAudioSession();
|
await AudioSession.startAudioSession();
|
||||||
|
console.log('[AudioSession] Android speaker mode configured!');
|
||||||
// CRITICAL: Explicitly select speaker AFTER session starts
|
|
||||||
// This overrides the default earpiece routing of inCommunication mode
|
|
||||||
try {
|
|
||||||
console.log('[AudioSession] Explicitly selecting speaker output...');
|
|
||||||
await AudioSession.selectAudioOutput('speaker');
|
|
||||||
console.log('[AudioSession] Speaker output explicitly selected!');
|
|
||||||
} catch (speakerErr) {
|
|
||||||
console.warn('[AudioSession] selectAudioOutput failed, trying showAudioRoutePicker:', speakerErr);
|
|
||||||
// Fallback: try to show audio route picker or use alternative method
|
|
||||||
try {
|
|
||||||
if (AudioSession.showAudioRoutePicker) {
|
|
||||||
await AudioSession.showAudioRoutePicker();
|
|
||||||
}
|
|
||||||
} catch (pickerErr) {
|
|
||||||
console.warn('[AudioSession] showAudioRoutePicker also failed:', pickerErr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[AudioSession] Android speaker mode with echo cancellation configured!');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[AudioSession] Configuration complete!');
|
console.log('[AudioSession] Configuration complete!');
|
||||||
@ -210,30 +192,22 @@ export async function reconfigureAudioForPlayback(): Promise<void> {
|
|||||||
});
|
});
|
||||||
console.log('[AudioSession] iOS reconfigured for speaker playback');
|
console.log('[AudioSession] iOS reconfigured for speaker playback');
|
||||||
} else if (Platform.OS === 'android') {
|
} else if (Platform.OS === 'android') {
|
||||||
// Reconfigure Android - force speaker while keeping echo cancellation
|
// Reconfigure Android audio to ensure speaker output
|
||||||
|
// Using 'music' stream type to force speaker
|
||||||
await AudioSession.configureAudio({
|
await AudioSession.configureAudio({
|
||||||
android: {
|
android: {
|
||||||
preferredOutputList: ['speaker'],
|
|
||||||
forceHandleAudioRouting: true,
|
|
||||||
audioTypeOptions: {
|
audioTypeOptions: {
|
||||||
manageAudioFocus: true,
|
manageAudioFocus: true,
|
||||||
audioMode: 'inCommunication', // Keep for echo cancellation
|
audioMode: 'normal',
|
||||||
audioFocusMode: 'gain',
|
audioFocusMode: 'gain',
|
||||||
audioStreamType: 'voiceCall',
|
audioStreamType: 'music',
|
||||||
audioAttributesUsageType: 'voiceCommunication',
|
audioAttributesUsageType: 'media',
|
||||||
audioAttributesContentType: 'speech',
|
audioAttributesContentType: 'music',
|
||||||
},
|
},
|
||||||
|
preferredOutputList: ['speaker'],
|
||||||
|
forceHandleAudioRouting: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Explicitly select speaker output
|
|
||||||
try {
|
|
||||||
await AudioSession.selectAudioOutput('speaker');
|
|
||||||
console.log('[AudioSession] Android speaker explicitly selected');
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('[AudioSession] selectAudioOutput failed in reconfigure:', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[AudioSession] Android reconfigured for speaker playback');
|
console.log('[AudioSession] Android reconfigured for speaker playback');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,29 +250,25 @@ export async function setAudioOutput(useSpeaker: boolean): Promise<void> {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (Platform.OS === 'android') {
|
} else if (Platform.OS === 'android') {
|
||||||
// Android: Keep inCommunication mode for echo cancellation, use explicit output selection
|
// Android: Switch stream type to control speaker/earpiece
|
||||||
|
// - 'music' stream goes to speaker by default
|
||||||
|
// - 'voiceCall' stream goes to earpiece by default
|
||||||
await AudioSession.configureAudio({
|
await AudioSession.configureAudio({
|
||||||
android: {
|
android: {
|
||||||
preferredOutputList: useSpeaker ? ['speaker'] : ['earpiece'],
|
|
||||||
forceHandleAudioRouting: true,
|
|
||||||
audioTypeOptions: {
|
audioTypeOptions: {
|
||||||
manageAudioFocus: true,
|
manageAudioFocus: true,
|
||||||
// Always use inCommunication for echo cancellation
|
audioMode: useSpeaker ? 'normal' : 'inCommunication',
|
||||||
audioMode: 'inCommunication',
|
|
||||||
audioFocusMode: 'gain',
|
audioFocusMode: 'gain',
|
||||||
audioStreamType: 'voiceCall',
|
// Key difference: music→speaker, voiceCall→earpiece
|
||||||
audioAttributesUsageType: 'voiceCommunication',
|
audioStreamType: useSpeaker ? 'music' : 'voiceCall',
|
||||||
audioAttributesContentType: 'speech',
|
audioAttributesUsageType: useSpeaker ? 'media' : 'voiceCommunication',
|
||||||
|
audioAttributesContentType: useSpeaker ? 'music' : 'speech',
|
||||||
},
|
},
|
||||||
|
// Also set preferred output list
|
||||||
|
preferredOutputList: useSpeaker ? ['speaker'] : ['earpiece'],
|
||||||
|
forceHandleAudioRouting: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Explicitly select output device
|
|
||||||
try {
|
|
||||||
await AudioSession.selectAudioOutput(useSpeaker ? 'speaker' : 'earpiece');
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('[AudioSession] selectAudioOutput failed:', err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[AudioSession] Audio output set to ${useSpeaker ? 'SPEAKER' : 'EARPIECE'}`);
|
console.log(`[AudioSession] Audio output set to ${useSpeaker ? 'SPEAKER' : 'EARPIECE'}`);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user