Skip to main content
The CometChat Calls SDK supports multiple audio output modes on mobile devices. Users can switch between speaker, earpiece, Bluetooth, and wired headphones.

Available Audio Modes

ModeConstantDescription
SpeakerCometChatCalls.AUDIO_MODE.SPEAKERPhone speaker (loudspeaker)
EarpieceCometChatCalls.AUDIO_MODE.EARPIECEPhone earpiece (for private calls)
BluetoothCometChatCalls.AUDIO_MODE.BLUETOOTHConnected Bluetooth device
HeadphonesCometChatCalls.AUDIO_MODE.HEADPHONESWired headphones

Set Default Audio Mode

Configure the default audio mode when creating call settings:
import { CometChatCalls } from '@cometchat/calls-sdk-react-native';

const callSettings = new CometChatCalls.CallSettingsBuilder()
  .setDefaultAudioMode(CometChatCalls.AUDIO_MODE.SPEAKER)
  .build();

Show Audio Mode Button

Enable the audio mode button in the call UI:
const callSettings = new CometChatCalls.CallSettingsBuilder()
  .showAudioModeButton(true)
  .build();

Listen for Audio Mode Changes

Subscribe to audio mode change events:
CometChatCalls.addEventListener('onAudioModeChanged', (mode) => {
  console.log('Audio mode changed to:', mode);
  // mode: 'SPEAKER' | 'EARPIECE' | 'BLUETOOTH' | 'HEADPHONES'
});

Using OngoingCallListener

Handle audio mode updates through the call settings listener:
const callListener = new CometChatCalls.OngoingCallListener({
  onAudioModesUpdated: (audioModes) => {
    console.log('Available audio modes:', audioModes);
    // audioModes is an array of available modes
  },
});

const callSettings = new CometChatCalls.CallSettingsBuilder()
  .setCallEventListener(callListener)
  .build();

Audio Mode Object

When receiving audio mode updates, each mode object contains:
PropertyTypeDescription
typestringMode type (SPEAKER, EARPIECE, BLUETOOTH, HEADPHONES)
selectedbooleanWhether this mode is currently active

Complete Example

import React, { useState, useEffect } from 'react';
import { View, TouchableOpacity, Text, StyleSheet, Modal, FlatList } from 'react-native';
import { CometChatCalls } from '@cometchat/calls-sdk-react-native';

type AudioMode = 'SPEAKER' | 'EARPIECE' | 'BLUETOOTH' | 'HEADPHONES';

interface AudioModeOption {
  type: AudioMode;
  label: string;
  icon: string;
}

const audioModeOptions: AudioModeOption[] = [
  { type: 'SPEAKER', label: 'Speaker', icon: '🔊' },
  { type: 'EARPIECE', label: 'Earpiece', icon: '📱' },
  { type: 'BLUETOOTH', label: 'Bluetooth', icon: '🎧' },
  { type: 'HEADPHONES', label: 'Headphones', icon: '🎵' },
];

function AudioModeSelector() {
  const [currentMode, setCurrentMode] = useState<AudioMode>('SPEAKER');
  const [availableModes, setAvailableModes] = useState<AudioMode[]>(['SPEAKER', 'EARPIECE']);
  const [modalVisible, setModalVisible] = useState(false);

  useEffect(() => {
    const unsubscribe = CometChatCalls.addEventListener(
      'onAudioModeChanged',
      (mode: AudioMode) => {
        setCurrentMode(mode);
      }
    );

    return () => unsubscribe();
  }, []);

  const selectMode = (mode: AudioMode) => {
    // The SDK handles audio mode switching through the UI
    // This is for display purposes
    setCurrentMode(mode);
    setModalVisible(false);
  };

  const getCurrentModeOption = () => {
    return audioModeOptions.find((opt) => opt.type === currentMode) || audioModeOptions[0];
  };

  const renderModeOption = ({ item }: { item: AudioModeOption }) => {
    const isAvailable = availableModes.includes(item.type);
    const isSelected = currentMode === item.type;

    return (
      <TouchableOpacity
        style={[
          styles.modeOption,
          isSelected && styles.selectedOption,
          !isAvailable && styles.disabledOption,
        ]}
        onPress={() => isAvailable && selectMode(item.type)}
        disabled={!isAvailable}
      >
        <Text style={styles.modeIcon}>{item.icon}</Text>
        <Text
          style={[
            styles.modeLabel,
            isSelected && styles.selectedLabel,
            !isAvailable && styles.disabledLabel,
          ]}
        >
          {item.label}
        </Text>
        {isSelected && <Text style={styles.checkmark}></Text>}
      </TouchableOpacity>
    );
  };

  return (
    <View>
      <TouchableOpacity
        style={styles.button}
        onPress={() => setModalVisible(true)}
      >
        <Text style={styles.buttonIcon}>{getCurrentModeOption().icon}</Text>
        <Text style={styles.buttonText}>{getCurrentModeOption().label}</Text>
      </TouchableOpacity>

      <Modal
        visible={modalVisible}
        transparent
        animationType="slide"
        onRequestClose={() => setModalVisible(false)}
      >
        <View style={styles.modalOverlay}>
          <View style={styles.modalContent}>
            <Text style={styles.modalTitle}>Audio Output</Text>
            <FlatList
              data={audioModeOptions}
              keyExtractor={(item) => item.type}
              renderItem={renderModeOption}
            />
            <TouchableOpacity
              style={styles.closeButton}
              onPress={() => setModalVisible(false)}
            >
              <Text style={styles.closeButtonText}>Close</Text>
            </TouchableOpacity>
          </View>
        </View>
      </Modal>
    </View>
  );
}

const styles = StyleSheet.create({
  button: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#333',
    paddingHorizontal: 16,
    paddingVertical: 12,
    borderRadius: 8,
    gap: 8,
  },
  buttonIcon: {
    fontSize: 18,
  },
  buttonText: {
    color: '#fff',
    fontSize: 14,
    fontWeight: '600',
  },
  modalOverlay: {
    flex: 1,
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
    justifyContent: 'flex-end',
  },
  modalContent: {
    backgroundColor: '#1a1a1a',
    borderTopLeftRadius: 20,
    borderTopRightRadius: 20,
    padding: 20,
  },
  modalTitle: {
    color: '#fff',
    fontSize: 18,
    fontWeight: '600',
    marginBottom: 16,
    textAlign: 'center',
  },
  modeOption: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 16,
    borderRadius: 8,
    marginBottom: 8,
    backgroundColor: '#333',
  },
  selectedOption: {
    backgroundColor: '#6851D6',
  },
  disabledOption: {
    opacity: 0.5,
  },
  modeIcon: {
    fontSize: 24,
    marginRight: 12,
  },
  modeLabel: {
    flex: 1,
    color: '#fff',
    fontSize: 16,
  },
  selectedLabel: {
    fontWeight: '600',
  },
  disabledLabel: {
    color: '#666',
  },
  checkmark: {
    color: '#fff',
    fontSize: 18,
  },
  closeButton: {
    marginTop: 16,
    padding: 16,
    alignItems: 'center',
  },
  closeButtonText: {
    color: '#6851D6',
    fontSize: 16,
    fontWeight: '600',
  },
});

export default AudioModeSelector;

Platform Considerations

iOS

  • Audio mode switching is handled automatically by iOS based on connected devices
  • Bluetooth devices appear when connected
  • Headphones are detected when plugged in

Android

  • Requires MODIFY_AUDIO_SETTINGS permission
  • Bluetooth requires BLUETOOTH and BLUETOOTH_CONNECT permissions
  • Audio routing may vary by device manufacturer