웨어러블 기기에서 오디오 재생

이 가이드에서는 친숙한 Android API를 사용하여 Wear OS 앱에서 오디오를 재생하는 방법을 설명합니다.

오디오 기기 감지

Wear OS 앱은 먼저 웨어러블 기기에 적절한 오디오 출력이 있는지 감지해야 합니다. 웨어러블 기기에는 일반적으로 다음 오디오 출력 중 하나 이상이 있습니다.

  • AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: 스피커가 내장된 기기
  • AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: 블루투스 헤드셋이 페어링 및 연결된 경우
  • AudioDeviceInfo.TYPE_BLE_BROADCAST: 저전력 블루투스 (BLE) 브로드캐스트 그룹 기기가 페어링 및 연결된 경우
  • AudioDeviceInfo.TYPE_BLE_HEADSET: BLE 헤드셋이 페어링 및 연결된 경우
  • AudioDeviceInfo.TYPE_BLE_SPEAKER: BLE 스피커가 페어링 및 연결된 경우

다음 예에서는 FEATURE_AUDIO_OUTPUT 값과 함께 getDevices() 메서드를 사용하여 오디오 출력 유형을 사용할 수 있는지 확인합니다.

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 }
}

그런 다음 이 메서드를 사용하여 오디오 출력 유형을 사용할 수 있는지 확인할 수 있습니다.

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)

최상의 사용자 환경을 제공하려면 블루투스 헤드폰이나 스피커가 시계에 연결되어 있을 때만 미디어를 재생하세요.

오디오 출력에 사용할 기본 기기 선택

앱의 사용 사례와 핵심 환경에 대한 오디오의 중요성에 따라 사용자가 앱의 오디오 출력에 어떻게 참여할 것인지 선택합니다.

사용자가 미디어 출력 기기를 선택하도록 허용

Wear OS 5부터 시스템은 사용자가 미디어를 재생할 기기를 선택하고 현재 재생 중인 미디어 콘텐츠에 관한 정보를 표시할 수 있는 UI를 제공합니다.

Wear OS 5 이상을 실행하는 기기에서 오디오 재생을 제공하려고 할 때 연결된 블루투스 헤드셋이 없음을 앱에서 감지하는 경우 사용자를 미디어 출력 전환기로 바로 안내하는 것이 좋습니다. 미디어 출력 전환기를 지원하지 않는 기기에서는 사용자를 시스템 설정의 블루투스 페이지로 안내하는 ACTION_BLUETOOTH_SETTINGS 인텐트 작업을 호출합니다.

GitHub의 Horologist 라이브러리의 일부인 launchOutputSelection() 메서드는 사용자가 미디어 출력 기기를 선택하도록 하는 방법을 보여줍니다.

블루투스 헤드셋

기기에 있는 경우 항상 사용할 수 있는 내장 스피커와 달리 블루투스 헤드셋은 앱이 실행되는 동안 페어링되거나 페어링 해제될 수 있습니다. 앱을 계속 진행하려면 헤드셋이 필요한 경우 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)

오디오 출력을 제공하려고 할 때 연결된 블루투스 헤드셋이 없음을 앱에서 감지하는 경우 오류 메시지를 표시하지 마세요. 대신 사용자가 더 쉽게 연결할 수 있도록 블루투스 설정으로 바로 이동하라고 제안합니다. 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

내장 스피커

대부분의 Wear OS 기기에는 내장 스피커가 있습니다. 앱이 사운드를 사용하는 미디어 외 사용 사례를 제공하는 경우 스피커를 사용하여 참여를 한층 더 높일 수 있습니다. 예를 들어 스피커가 장착된 Wear OS 기기는 오디오 알림이 포함된 시계나 타이머 알람을 트리거하고 피트니스 앱은 스피커를 사용하여 운동 안내를 제공할 수 있습니다.

자세한 내용은 WearSpeakerSample을 참고하세요.

오디오 재생

적절한 오디오 출력이 감지되고 선택되면 Wear OS에서 오디오를 재생하는 프로세스는 모바일 또는 기타 기기에서와 동일합니다. 자세한 내용은 MediaPlayer 개요를 참고하세요. 미디어 스트리밍 및 다운로드와 같은 고급 기능에 더 쉽게 액세스하려면 ExoPlayer를 사용하세요. 오디오 앱 권장사항(예: 오디오 포커스 관리)을 따릅니다.

내장 스피커를 통한 의도하지 않은 미디어 재생 방지

미디어 앱은 이 안내에 따라 앱이 의도치 않게 내장 시계 스피커에서 미디어를 재생하지 않도록 할 수 있습니다. 안내는 앱에서 사용하는 플레이어에 따라 다릅니다.

ExoPlayer

앱에서 ExoPlayer를 사용하는 경우:

  1. ExoPlayer 인스턴스를 빌드하는 동안 setSuppressPlaybackOnUnsuitableOutput(true) 메서드를 호출합니다.

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

  1. WearUnsuitableOutputPlaybackSuppressionResolverListener listener를 ExoPlayer 인스턴스의 리스너로 등록하여 재생 억제 이벤트에 반응합니다.

exoPlayer.addListener(WearUnsuitableOutputPlaybackSuppressionResolverListener(context))

Horologist 미디어 툴킷

Horologist MediaToolkit에는 내장된 시계 스피커에서 의도치 않은 미디어 재생을 방지하는 로직이 이미 포함되어 있습니다.

기타 미디어 플레이어