Skip to content

TechNote_BluetoothAudio

Robert Wu edited this page Jan 13, 2022 · 9 revisions

Bluetooth Audio

Bluetooth audio devices work differently during a phone call and listening to music. All Bluetooth audio devices should expose two endpoints, A2DP and SCO.

A2DP (Advanced Audio Distribution Profile)

A2DP is a protocol supported on all Bluetooth Audio devices. This protocol is used for high quality music.

To achieve high quality music, Android encodes music with a codec. The headset receives this data and decodes it into PCM data. Android and all headsets must support the SBC codec. Additional codecs like aptX, AAC, and LDAC are supported on a per device basis.

SCO (Synchronous Connection Oriented Link)

During a voice call, SCO is used. The underlying protocols HSP/HFP are supported on all Bluetooth devices. HSP (HeadSet Profile) is used for voice communication and HFP (Hands-Free Profile) was meant to control a phone from another unit.

Compared to A2DP, SCO has worse audio quality but lower latency.

Enabling SCO

If SCO device is currently used in an App, there could be no audio playing from the headset. The function below checks whether an Audio device's type is SCO. Likewise, you write a for loop to pick a SCO device instead of an A2DP device.

    @RequiresApi(api = Build.VERSION_CODES.M)
    private boolean isScoDevice(int deviceId) {
        if (deviceId == 0) return false; // Unspecified
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        final AudioDeviceInfo[] devices;
        devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
        for (AudioDeviceInfo device : devices) {
            if (device.getId() == deviceId) {
                return device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
            }
        }
        return false;
    }

After confirming the Bluetooth device is currently a SCO device, you should start Bluetooth SCO in the OS.

    private void startBluetoothSco() {
        AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        myAudioMgr.startBluetoothSco();
    }

See HelloOboe for a full example of turning on a Bluetooth SCO device when the Bluetooth SCO endpoint is selected.

How to reduce the latency of a headset

In most cases, Android itself has a latency between 30-100 ms. Most of the latency comes from buffering on various headsets.

If a specific headset has a high latency, try changing the Bluetooth Audio Codec in developer settings. Also, try toggling "Disable Bluetooth A2DP hardware offload".