Tocar áudio em wearables

Este guia descreve como usar APIs conhecidas do Android para tocar áudio em apps para Wear OS.

Detectar dispositivos de áudio

Os apps para Wear OS precisam primeiro detectar se o dispositivo wearable tem uma saída de áudio adequada. Os dispositivos wearables geralmente têm pelo menos uma das seguintes saídas de áudio:

  • AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: em dispositivos com um alto-falante integrado.
  • AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: quando um fone de ouvido Bluetooth estiver pareado e conectado.
  • AudioDeviceInfo.TYPE_BLE_BROADCAST: quando um dispositivo do grupo de transmissão Bluetooth de baixa energia (BLE) estiver pareado e conectado.
  • AudioDeviceInfo.TYPE_BLE_HEADSET: quando um fone de ouvido BLE estiver pareado e conectado.
  • AudioDeviceInfo.TYPE_BLE_SPEAKER: quando um alto-falante BLE estiver pareado e conectado.

O exemplo a seguir usa o método getDevices() com o valor FEATURE_AUDIO_OUTPUT para verificar se um tipo de saída de áudio está disponível.

private val audioManager: AudioManager by lazy {
    getSystemService(AUDIO_SERVICE) as AudioManager
}

fun audioOutputAvailable(type: Int): Boolean {
    if (!packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
        return false
    }
    return audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS).any { it.type == type }
}

Em seguida, use esse método para verificar se um tipo de saída de áudio está disponível.

val hasSpeaker = audioOutputAvailable(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER)
val hasBluetoothHeadset = audioOutputAvailable(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP)
val hasBLEBroadcast = audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_BROADCAST)
val hasBLEHeadset = audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_HEADSET)
val hasBLESpeaker = audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_SPEAKER)

Para oferecer a melhor experiência do usuário, toque mídia somente quando fones de ouvido com Bluetooth ou alto-falantes estiverem conectados ao relógio.

Escolher o dispositivo preferido para saída de áudio

Dependendo do caso de uso do seu app e da importância do áudio para a experiência principal dele, escolha como você quer que os usuários interajam com a saída de áudio.

Permitir que o usuário escolha o dispositivo de saída de mídia

A partir do Wear OS 5, o sistema oferece uma interface que permite aos usuários escolher qual dispositivo toca mídia e mostra informações sobre o conteúdo de mídia em reprodução.

Se o app detectar que não há um fone de ouvido Bluetooth conectado quando você quiser fornecer reprodução de áudio em dispositivos com o Wear OS 5 ou mais recente, ofereça a opção de direcionar o usuário diretamente para o seletor de saída de mídia. Em dispositivos que não oferecem suporte ao seletor de saída de mídia, chame a ação de ACTION_BLUETOOTH_SETTINGS intent, que leva o usuário à página do Bluetooth nas configurações do sistema.

O launchOutputSelection() método, que faz parte da biblioteca Horologist no GitHub (link em inglês), demonstra como permitir que os usuários escolham o dispositivo de saída de mídia.

Fone de ouvido Bluetooth

Ao contrário dos alto-falantes integrados, que estão sempre disponíveis se estiverem presentes no dispositivo, um fone de ouvido Bluetooth pode ser pareado ou não enquanto um app está em execução. Se o app exigir que um fone de ouvido seja conectado para continuar, registre um callback para detectar quando o usuário conecta e desconecta o fone de ouvido Bluetooth usando registerAudioDeviceCallback:

val audioDeviceCallback =
    object : AudioDeviceCallback() {
        override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
            super.onAudioDevicesAdded(addedDevices)
            if (audioOutputAvailable(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) ||
                audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_BROADCAST) ||
                audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_HEADSET) ||
                audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_SPEAKER)
            ) {
                // A Bluetooth or BLE device is connected and available for playback.
            }
        }
        override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) {
            super.onAudioDevicesRemoved(removedDevices)
            if (!(audioOutputAvailable(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP)) &&
                !(audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_BROADCAST)) &&
                !(audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_HEADSET)) &&
                !(audioOutputAvailable(AudioDeviceInfo.TYPE_BLE_SPEAKER))
            ) {
                // No Bluetooth or BLE devices are connected anymore.
            }
        }
    }

audioManager.registerAudioDeviceCallback(audioDeviceCallback, /*handler=*/ null)

Se o app detectar que não há um fone de ouvido Bluetooth conectado quando você quiser fornecer uma saída de áudio, não mostre uma mensagem de erro. Em vez disso, ofereça a opção de direcionar o usuário às configurações de Bluetooth para facilitar a conexão. Para fazer isso, envie uma intent com ACTION_BLUETOOTH_SETTINGS:

fun Context.launchBluetoothSettings(closeOnConnect: Boolean = true) {
    val intent = with(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) {
        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
        putExtra("EXTRA_CONNECTION_ONLY", true)
        if (closeOnConnect) {
            putExtra("EXTRA_CLOSE_ON_CONNECT", true)
        }
        putExtra("android.bluetooth.devicepicker.extra.FILTER_TYPE", FILTER_TYPE_AUDIO)
    }
    startActivity(intent)
}

internal const val FILTER_TYPE_AUDIO = 1

Alto-falantes integrados

A maioria dos dispositivos Wear OS tem alto-falantes integrados. Se o app oferece um caso de uso que não é de mídia e usa som, use alto-falantes para oferecer uma dimensão extra de engajamento. Por exemplo, um dispositivo Wear OS com alto-falantes pode acionar alarmes de relógio ou timers com notificações de áudio, e os apps fitness podem usar o alto-falante para fornecer instruções de exercício.

Consulte WearSpeakerSample (link em inglês) para mais detalhes.

Tocar o áudio

Depois de detectar e escolher uma saída de áudio adequada, o processo para tocar áudio no Wear OS é o mesmo usado em dispositivos móveis ou de outros tipos. Para saber mais, consulte Visão geral da MediaPlayer. Para facilitar o acesso a recursos avançados, por exemplo, streaming e download de mídia, use o ExoPlayer. Siga as práticas recomendadas para apps de áudio, por exemplo, gerenciar a seleção de áudio.

Impedir a reprodução não intencional de mídia pelos alto-falantes integrados

Os apps de mídia podem seguir estas orientações para evitar que o app toque mídia de forma não intencional nos alto-falantes integrados do relógio. As orientações variam dependendo do player usado pelo app.

ExoPlayer

Se o app usa o ExoPlayer:

  1. Chame setSuppressPlaybackOnUnsuitableOutput(true) método ao criar a instância do ExoPlayer:

val exoPlayer = ExoPlayer.Builder(context)
    .setAudioAttributes(AudioAttributes.DEFAULT, true)
    .setSuppressPlaybackOnUnsuitableOutput(true)
    .build()

  1. Reaja ao evento de supressão de reprodução registrando WearUnsuitableOutputPlaybackSuppressionResolverListener listener como um listener da instância do ExoPlayer:

exoPlayer.addListener(WearUnsuitableOutputPlaybackSuppressionResolverListener(context))

Kit de ferramentas de mídia do Horologist

O Horologist MediaToolkit já contém lógica para evitar a reprodução não intencional de mídia em alto-falantes integrados do relógio.

Outros players de mídia