如何在Amazon Chime React Native SDK会议开始前配置设备
问题场景
在使用amazon-chime-react-native开发App时,当前只有调用startMeeting后才能获取设备列表,但在设置页面启动会议会直接听到其他参会者的声音,因此NativeFunction.startMeeting必须放在会议页面执行。需要实现先初始化媒体会话(不加入会议)来获取设备列表,再在会议页面正式启动会议的流程。
核心解决方案
Amazon Chime SDK允许在不加入真实会议的情况下初始化媒体模块枚举设备。我们需要在Native层新增初始化临时媒体会话的方法,让设置页面能提前获取设备列表,进入会议前销毁临时会话,再在会议页面正式启动会议并应用用户选择的设备。
1. Android端修改(NativeMobileSDKBridge.kt)
新增临时媒体会话的初始化、销毁方法,并修改设备列表获取逻辑:
// 新增:初始化临时媒体会话(仅用于设备枚举,不连接真实会议) fun initializeMediaSession() { val meetingConfiguration = MeetingConfiguration() val audioVideoConfiguration = AudioVideoConfiguration().apply { enableAudio = true enableVideo = true } meetingConfiguration.audioVideoConfiguration = audioVideoConfiguration // 使用空凭证创建临时会话配置 val meetingSessionConfiguration = MeetingSessionConfiguration( MeetingCredentials("", "", ""), meetingConfiguration ) meetingSession = DefaultMeetingSession( meetingSessionConfiguration, ConsoleLogger(Level.INFO), applicationContext ) // 启动音频模块以枚举设备 meetingSession?.audioVideo?.start() } // 修改:确保未初始化会话时也能返回设备列表 fun getAudieDevicesList(): WritableMap{ meetingSession ?: initializeMediaSession() val listAudioDevices = meetingSession?.audioVideo?.listAudioDevices() val map: WritableMap = WritableNativeMap() val list: WritableArray = WritableNativeArray() listAudioDevices?.forEach { val device: WritableMap = WritableNativeMap().apply { putString("id", it.id) putString("label", it.label) putString("type", it.type.name) } list.pushMap(device) } map.putArray("devices", list) return map } // 新增:销毁临时媒体会话 fun destroyMediaSession() { meetingSession?.audioVideo?.stop() meetingSession = null }
2. iOS端修改(NativeMobileSDKBridge.m)
新增对应方法并调整设备列表获取逻辑:
// 新增:初始化临时媒体会话 RCT_EXPORT_METHOD(initializeMediaSession) { MeetingConfiguration *meetingConfig = [[MeetingConfiguration alloc] init]; AudioVideoConfiguration *avConfig = [[AudioVideoConfiguration alloc] init]; avConfig.enableAudio = YES; avConfig.enableVideo = YES; meetingConfig.audioVideoConfiguration = avConfig; // 创建空凭证的临时会话配置 MeetingCredentials *credentials = [[MeetingCredentials alloc] initWithMeetingId:@"" attendeeId:@"" externalUserId:@""]; MeetingSessionConfiguration *sessionConfig = [[MeetingSessionConfiguration alloc] initWithMeetingCredentials:credentials configuration:meetingConfig]; meetingSession = [[DefaultMeetingSession alloc] initWithConfiguration:sessionConfig logger:[ConsoleLogger loggerWithLogLevel:LogLevelInfo]]; [meetingSession.audioVideo start]; } // 修改:自动初始化会话以获取设备列表 RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getAudieDevicesList) { if (!meetingSession) { [self initializeMediaSession]; } NSArray *deviceList = [meetingSession.audioVideo listAudioDevices]; NSMutableArray *transformedList = [NSMutableArray array]; for (MediaDevice * device in deviceList) { [transformedList addObject:@{ @"label": device.label ?: @"Unknown", @"type": [NSString stringWithFormat:@"%i", device.type], @"id": device.id ?: @"" }]; } return @{@"devices":transformedList}; } // 新增:销毁临时媒体会话 RCT_EXPORT_METHOD(destroyMediaSession) { [meetingSession.audioVideo stop]; meetingSession = nil; }
3. React Native层修改(Bridge.ts)
在NativeFunction中新增初始化、销毁临时会话的方法:
export const NativeFunction = { // 新增临时会话操作方法 initializeMediaSession: NativeModules.NativeMobileSDKBridge.initializeMediaSession, destroyMediaSession: NativeModules.NativeMobileSDKBridge.destroyMediaSession, // 原有方法保留 startMeeting: NativeModules.NativeMobileSDKBridge.startMeeting, stopMeeting: NativeModules.NativeMobileSDKBridge.stopMeeting, setMute: NativeModules.NativeMobileSDKBridge.setMute, setAudioDevice: NativeModules.NativeMobileSDKBridge.setAudioDevice, getAudioDevicesList: NativeModules.NativeMobileSDKBridge.getAudieDevicesList, setCameraOn: NativeModules.NativeMobileSDKBridge.setCameraOn, bindVideoView: NativeModules.NativeMobileSDKBridge.bindVideoView, unbindVideoView: NativeModules.NativeMobileSDKBridge.unbindVideoView, switchCamera: NativeModules.NativeMobileSDKBridge.switchCamera, sendDataMessage: NativeModules.NativeMobileSDKBridge.sendDataMessage, };
4. 设备设置页面修改(DeviceSetup.tsx)
调整设备获取逻辑,离开时销毁临时会话并传递选中设备参数:
const DeviceSetup: FC<Props> = ({ route }) => { const navigation = useNavigation(); const [microphones, setMicrophones] = useState([]); const [selectedMicrophone, setSelectedMicrophone] = useState(); const [speakers, setSpeakers] = useState([]); const [selectedSpeaker, setSelectedSpeaker] = useState(); const handleJoinToCall = useCallback( async () => { // 销毁临时会话后进入会议页面 await NativeFunction.destroyMediaSession(); navigation.dispatch( CommonActions.reset({ index: 1, routes: [ { name: PATHS.CALL, params: { ...route.params, selectedMicrophone, selectedSpeaker }, }, ], }) ); }, [selectedMicrophone, selectedSpeaker] ); const refreshDevices = useCallback(async () => { // 初始化临时会话后获取设备列表 await NativeFunction.initializeMediaSession(); const deviceList = await NativeFunction.getAudioDevicesList(); const microphonesList = deviceList?.devices.filter( (x: AudioDevice) => x.type === 'AUDIO_HANDSET' || x.type === '3' ); const speakersList = deviceList?.devices.filter( (x: AudioDevice) => x.type === 'AUDIO_BUILTIN_SPEAKER' || x.type === '2' ); setMicrophones(microphonesList || []); setSelectedMicrophone(microphonesList?.[0]); setSpeakers(speakersList || []); setSelectedSpeaker(speakersList?.[0]); }, []); // 原有requestPermissions、onDeviceChange逻辑保留不变 useEffect(() => { requestPermissions(); // 组件卸载时自动销毁临时会话 return () => { NativeFunction.destroyMediaSession(); }; }, []); // 原有UI代码保留不变 }; export default DeviceSetup;
5. 会议页面修改(Call.tsx)
正式启动会议并应用用户选中的设备:
const Call: FC<Props> = ({ route }) => { const { selectedMicrophone, selectedSpeaker, meetingId, userName } = route.params; useEffect(() => { const startMeeting = async () => { // 正式启动会议 await NativeFunction.startMeeting(meetingId, userName); // 应用用户选择的音频设备 if (selectedMicrophone) { await NativeFunction.setAudioDevice(selectedMicrophone.id); } if (selectedSpeaker) { await NativeFunction.setAudioDevice(selectedSpeaker.id); } }; startMeeting(); return () => { NativeFunction.stopMeeting(); }; }, []); // 会议页面其他逻辑保留不变 }; export default Call;
内容的提问来源于stack exchange,提问作者IncognitoUser
相关产品推荐
相关产品推荐

