1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16 
17 package com.android.settingslib.media.data.repository
18 
19 import android.media.AudioDeviceAttributes
20 import android.media.Spatializer
21 import kotlin.coroutines.CoroutineContext
22 import kotlinx.coroutines.withContext
23 
24 interface SpatializerRepository {
25 
26     /**
27      * Returns true when head tracking is available for the [audioDeviceAttributes] and false the
28      * otherwise.
29      */
isHeadTrackingAvailableForDevicenull30     suspend fun isHeadTrackingAvailableForDevice(
31         audioDeviceAttributes: AudioDeviceAttributes
32     ): Boolean
33 
34     /**
35      * Returns true when Spatial audio feature is supported for the [audioDeviceAttributes] and
36      * false the otherwise.
37      */
38     suspend fun isSpatialAudioAvailableForDevice(
39         audioDeviceAttributes: AudioDeviceAttributes
40     ): Boolean
41 
42     /** Returns a list [AudioDeviceAttributes] that are compatible with spatial audio. */
43     suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes>
44 
45     /** Adds a [audioDeviceAttributes] to [getSpatialAudioCompatibleDevices] list. */
46     suspend fun addSpatialAudioCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
47 
48     /** Removes a [audioDeviceAttributes] from [getSpatialAudioCompatibleDevices] list. */
49     suspend fun removeSpatialAudioCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
50 
51     /** Checks if the head tracking is enabled for the [audioDeviceAttributes]. */
52     suspend fun isHeadTrackingEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean
53 
54     /** Sets head tracking [isEnabled] for the [audioDeviceAttributes]. */
55     suspend fun setHeadTrackingEnabled(
56         audioDeviceAttributes: AudioDeviceAttributes,
57         isEnabled: Boolean,
58     )
59 }
60 
61 class SpatializerRepositoryImpl(
62     private val spatializer: Spatializer,
63     private val backgroundContext: CoroutineContext,
64 ) : SpatializerRepository {
65 
66     override suspend fun isHeadTrackingAvailableForDevice(
67         audioDeviceAttributes: AudioDeviceAttributes
68     ): Boolean {
69         return withContext(backgroundContext) { spatializer.hasHeadTracker(audioDeviceAttributes) }
70     }
71 
72     override suspend fun isSpatialAudioAvailableForDevice(
73         audioDeviceAttributes: AudioDeviceAttributes
74     ): Boolean {
75         return withContext(backgroundContext) {
76             spatializer.isAvailableForDevice(audioDeviceAttributes)
77         }
78     }
79 
80     override suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes> =
81         withContext(backgroundContext) { spatializer.compatibleAudioDevices }
82 
83     override suspend fun addSpatialAudioCompatibleDevice(
84         audioDeviceAttributes: AudioDeviceAttributes
85     ) {
86         withContext(backgroundContext) {
87             spatializer.addCompatibleAudioDevice(audioDeviceAttributes)
88         }
89     }
90 
91     override suspend fun removeSpatialAudioCompatibleDevice(
92         audioDeviceAttributes: AudioDeviceAttributes
93     ) {
94         withContext(backgroundContext) {
95             spatializer.removeCompatibleAudioDevice(audioDeviceAttributes)
96         }
97     }
98 
99     override suspend fun isHeadTrackingEnabled(
100         audioDeviceAttributes: AudioDeviceAttributes
101     ): Boolean =
102         withContext(backgroundContext) { spatializer.isHeadTrackerEnabled(audioDeviceAttributes) }
103 
104     override suspend fun setHeadTrackingEnabled(
105         audioDeviceAttributes: AudioDeviceAttributes,
106         isEnabled: Boolean,
107     ) {
108         withContext(backgroundContext) {
109             spatializer.setHeadTrackerEnabled(isEnabled, audioDeviceAttributes)
110         }
111     }
112 }
113