ウェアラブルで音声を再生する

このガイドでは、使い慣れた Android API を使用して Wear OS アプリでオーディオを再生する方法について説明します。

オーディオ機器を検出する

Wear OS アプリは、まずウェアラブル デバイスに適切なオーディオ出力があるかどうかを検出する必要があります。通常、ウェアラブル デバイスには以下のオーディオ出力の 1 つ以上があります。

  • AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: スピーカーを内蔵しているデバイスの場合。
  • AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: Bluetooth ヘッドセットがペア設定され、接続されている場合。
  • AudioDeviceInfo.TYPE_BLE_BROADCAST: Bluetooth Low Energy(BLE)ブロードキャスト グループ デバイスがペア設定され、接続されている場合。
  • AudioDeviceInfo.TYPE_BLE_HEADSET: BLE ヘッドセットがペア設定され、接続されている場合。
  • AudioDeviceInfo.TYPE_BLE_SPEAKER: BLE スピーカーがペア設定され、接続されている場合。

次の例では、getDevices() メソッドと FEATURE_AUDIO_OUTPUT 値を使用して、オーディオ出力タイプが使用可能かどうかを確認します。

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)

最適なユーザー エクスペリエンスを提供するため、Bluetooth ヘッドフォンまたはスピーカーがスマートウォッチに接続されている場合にのみ、メディアを再生します。

オーディオを出力する優先デバイスを選択する

アプリのユースケースと、アプリのコア エクスペリエンスに対するオーディオの重要性に応じて、ユーザーがアプリのオーディオ出力を操作する方法を選択します。

ユーザーがメディア出力デバイスを選択できるようにする

Wear OS 5 以降では、メディアを再生するデバイスを選択したり、現在再生中のメディア コンテンツに関する情報を表示したりできる UI が提供されます。

Wear OS 5 以降を搭載したデバイスでオーディオ再生を提供しようとしているときに、Bluetooth ヘッドセットが接続されていないことをアプリが検出した場合、ユーザーをメディア出力切り替えツールに直接移動することを提案します。メディア出力スイッチャーをサポートしていないデバイスでは、ACTION_BLUETOOTH_SETTINGS インテント アクションを呼び出して、ユーザーをシステム設定の Bluetooth ページに移動させます。

GitHub の Horologist ライブラリの一部である launchOutputSelection() メソッドは、ユーザーがメディア出力デバイスを選択できるようにする方法を示しています。

Bluetooth ヘッドセット

搭載されていれば常に利用できる内蔵スピーカーとは異なり、Bluetooth ヘッドセットは、アプリの実行中にペア設定されたり、ペア設定を解除されたりすることがあります。アプリで次に進むためにヘッドセットが必要な場合は、registerAudioDeviceCallback を使用して、ユーザーが Bluetooth ヘッドセットを接続もしくは切断したことを検出するコールバックを登録します。

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)

アプリがオーディオ出力を提供しようとしているときに、Bluetooth ヘッドセットが接続されていないことをアプリが検出した場合、エラー メッセージは表示しないでください。代わりに、ユーザーが簡単に接続できるように Bluetooth 設定に直接移動することを提案します。そのためには、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 Media ツールキット

Horologist MediaToolkit には、内蔵スマートウォッチ スピーカーでの意図しないメディア再生を防ぐロジックがすでに含まれています。

その他のメディア プレーヤー