• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 package android.car.media;
17 
18 import android.annotation.NonNull;
19 import android.annotation.SystemApi;
20 import android.car.CarLibLog;
21 import android.car.CarManagerBase;
22 import android.car.CarNotConnectedException;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.database.ContentObserver;
26 import android.media.AudioAttributes;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.RemoteException;
30 import android.provider.Settings;
31 import android.util.Log;
32 
33 /**
34  * APIs for handling car specific audio stuff.
35  */
36 public final class CarAudioManager implements CarManagerBase {
37 
38     // The trailing slash forms a directory-liked hierarchy and
39     // allows listening for both GROUP/MEDIA and GROUP/NAVIGATION.
40     private static final String VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX = "android.car.VOLUME_GROUP/";
41 
42     /**
43      * @param groupId The volume group id
44      * @return Key to persist volume index for volume group in {@link Settings.Global}
45      */
getVolumeSettingsKeyForGroup(int groupId)46     public static String getVolumeSettingsKeyForGroup(int groupId) {
47         return VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX + groupId;
48     }
49 
50     private final ContentResolver mContentResolver;
51     private final ICarAudio mService;
52 
53     /**
54      * Registers a {@link ContentObserver} to listen for volume group changes.
55      * Note that this observer is valid for bus based car audio stack only.
56      *
57      * {@link ContentObserver#onChange(boolean)} will be called on every group volume change.
58      *
59      * @param observer The {@link ContentObserver} instance to register, non-null
60      */
61     @SystemApi
registerVolumeChangeObserver(@onNull ContentObserver observer)62     public void registerVolumeChangeObserver(@NonNull ContentObserver observer) {
63         mContentResolver.registerContentObserver(
64                 Settings.Global.getUriFor(VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX),
65                 true, observer);
66     }
67 
68     /**
69      * Unregisters the {@link ContentObserver} which listens for volume group changes.
70      *
71      * @param observer The {@link ContentObserver} instance to unregister, non-null
72      */
73     @SystemApi
unregisterVolumeChangeObserver(@onNull ContentObserver observer)74     public void unregisterVolumeChangeObserver(@NonNull ContentObserver observer) {
75         mContentResolver.unregisterContentObserver(observer);
76     }
77 
78     /**
79      * Sets the volume index for a volume group.
80      *
81      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
82      *
83      * @param groupId The volume group id whose volume index should be set.
84      * @param index The volume index to set. See
85      *            {@link #getGroupMaxVolume(int)} for the largest valid value.
86      * @param flags One or more flags (e.g., {@link android.media.AudioManager#FLAG_SHOW_UI},
87      *              {@link android.media.AudioManager#FLAG_PLAY_SOUND})
88      */
89     @SystemApi
setGroupVolume(int groupId, int index, int flags)90     public void setGroupVolume(int groupId, int index, int flags) throws CarNotConnectedException {
91         try {
92             mService.setGroupVolume(groupId, index, flags);
93         } catch (RemoteException e) {
94             Log.e(CarLibLog.TAG_CAR, "setGroupVolume failed", e);
95             throw new CarNotConnectedException(e);
96         }
97     }
98 
99     /**
100      * Returns the maximum volume index for a volume group.
101      *
102      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
103      *
104      * @param groupId The volume group id whose maximum volume index is returned.
105      * @return The maximum valid volume index for the given group.
106      */
107     @SystemApi
getGroupMaxVolume(int groupId)108     public int getGroupMaxVolume(int groupId) throws CarNotConnectedException {
109         try {
110             return mService.getGroupMaxVolume(groupId);
111         } catch (RemoteException e) {
112             Log.e(CarLibLog.TAG_CAR, "getUsageMaxVolume failed", e);
113             throw new CarNotConnectedException(e);
114         }
115     }
116 
117     /**
118      * Returns the minimum volume index for a volume group.
119      *
120      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
121      *
122      * @param groupId The volume group id whose minimum volume index is returned.
123      * @return The minimum valid volume index for the given group, non-negative
124      */
125     @SystemApi
getGroupMinVolume(int groupId)126     public int getGroupMinVolume(int groupId) throws CarNotConnectedException {
127         try {
128             return mService.getGroupMinVolume(groupId);
129         } catch (RemoteException e) {
130             Log.e(CarLibLog.TAG_CAR, "getUsageMinVolume failed", e);
131             throw new CarNotConnectedException(e);
132         }
133     }
134 
135     /**
136      * Returns the current volume index for a volume group.
137      *
138      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
139      *
140      * @param groupId The volume group id whose volume index is returned.
141      * @return The current volume index for the given group.
142      *
143      * @see #getGroupMaxVolume(int)
144      * @see #setGroupVolume(int, int, int)
145      */
146     @SystemApi
getGroupVolume(int groupId)147     public int getGroupVolume(int groupId) throws CarNotConnectedException {
148         try {
149             return mService.getGroupVolume(groupId);
150         } catch (RemoteException e) {
151             Log.e(CarLibLog.TAG_CAR, "getUsageVolume failed", e);
152             throw new CarNotConnectedException(e);
153         }
154     }
155 
156     /**
157      * Adjust the relative volume in the front vs back of the vehicle cabin.
158      *
159      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
160      *
161      * @param value in the range -1.0 to 1.0 for fully toward the back through
162      *              fully toward the front.  0.0 means evenly balanced.
163      *
164      * @see #setBalanceTowardRight(float)
165      */
166     @SystemApi
setFadeTowardFront(float value)167     public void setFadeTowardFront(float value) throws CarNotConnectedException {
168         try {
169             mService.setFadeTowardFront(value);
170         } catch (RemoteException e) {
171             Log.e(CarLibLog.TAG_CAR, "setFadeTowardFront failed", e);
172             throw new CarNotConnectedException(e);
173         }
174     }
175 
176     /**
177      * Adjust the relative volume on the left vs right side of the vehicle cabin.
178      *
179      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
180      *
181      * @param value in the range -1.0 to 1.0 for fully toward the left through
182      *              fully toward the right.  0.0 means evenly balanced.
183      *
184      * @see #setFadeTowardFront(float)
185      */
186     @SystemApi
setBalanceTowardRight(float value)187     public void setBalanceTowardRight(float value) throws CarNotConnectedException {
188         try {
189             mService.setBalanceTowardRight(value);
190         } catch (RemoteException e) {
191             Log.e(CarLibLog.TAG_CAR, "setBalanceTowardRight failed", e);
192             throw new CarNotConnectedException(e);
193         }
194     }
195 
196     /**
197      * Queries the system configuration in order to report the available, non-microphone audio
198      * input devices.
199      *
200      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
201      *
202      * @return An array of strings representing the available input ports.
203      * Each port is identified by it's "address" tag in the audioPolicyConfiguration xml file.
204      * Empty array if we find nothing.
205      *
206      * @see #createAudioPatch(String, int, int)
207      * @see #releaseAudioPatch(CarAudioPatchHandle)
208      */
209     @SystemApi
getExternalSources()210     public @NonNull String[] getExternalSources() throws CarNotConnectedException {
211         try {
212             return mService.getExternalSources();
213         } catch (RemoteException e) {
214             Log.e(CarLibLog.TAG_CAR, "getExternalSources failed", e);
215             throw new CarNotConnectedException(e);
216         }
217     }
218 
219     /**
220      * Given an input port identified by getExternalSources(), request that it's audio signal
221      * be routed below the HAL to the output port associated with the given usage.  For example,
222      * The output of a tuner might be routed directly to the output buss associated with
223      * AudioAttributes.USAGE_MEDIA while the tuner is playing.
224      *
225      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
226      *
227      * @param sourceAddress the input port name obtained from getExternalSources().
228      * @param usage the type of audio represented by this source (usually USAGE_MEDIA).
229      * @param gainInMillibels How many steps above the minimum value defined for the source port to
230      *                       set the gain when creating the patch.
231      *                       This may be used for source balancing without affecting the user
232      *                       controlled volumes applied to the destination ports.  A value of
233      *                       0 indicates no gain change is requested.
234      * @return A handle for the created patch which can be used to later remove it.
235      *
236      * @see #getExternalSources()
237      * @see #releaseAudioPatch(CarAudioPatchHandle)
238      */
239     @SystemApi
createAudioPatch(String sourceAddress, @AudioAttributes.AttributeUsage int usage, int gainInMillibels)240     public CarAudioPatchHandle createAudioPatch(String sourceAddress,
241             @AudioAttributes.AttributeUsage int usage, int gainInMillibels)
242             throws CarNotConnectedException {
243         try {
244             return mService.createAudioPatch(sourceAddress, usage, gainInMillibels);
245         } catch (RemoteException e) {
246             Log.e(CarLibLog.TAG_CAR, "createAudioPatch failed", e);
247             throw new CarNotConnectedException(e);
248         }
249     }
250 
251     /**
252      * Removes the association between an input port and an output port identified by the provided
253      * handle.
254      *
255      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
256      *
257      * @param patch CarAudioPatchHandle returned from createAudioPatch().
258      *
259      * @see #getExternalSources()
260      * @see #createAudioPatch(String, int, int)
261      */
262     @SystemApi
releaseAudioPatch(CarAudioPatchHandle patch)263     public void releaseAudioPatch(CarAudioPatchHandle patch) throws CarNotConnectedException {
264         try {
265             mService.releaseAudioPatch(patch);
266         } catch (RemoteException e) {
267             Log.e(CarLibLog.TAG_CAR, "releaseAudioPatch failed", e);
268             throw new CarNotConnectedException(e);
269         }
270     }
271 
272     /**
273      * Gets the count of available volume groups in the system.
274      *
275      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
276      *
277      * @return Count of volume groups
278      */
279     @SystemApi
getVolumeGroupCount()280     public int getVolumeGroupCount() throws CarNotConnectedException {
281         try {
282             return mService.getVolumeGroupCount();
283         } catch (RemoteException e) {
284             Log.e(CarLibLog.TAG_CAR, "getVolumeGroupCount failed", e);
285             throw new CarNotConnectedException(e);
286         }
287     }
288 
289     /**
290      * Gets the volume group id for a given {@link AudioAttributes} usage.
291      *
292      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
293      *
294      * @param usage The {@link AudioAttributes} usage to get a volume group from.
295      * @return The volume group id where the usage belongs to
296      */
297     @SystemApi
getVolumeGroupIdForUsage(@udioAttributes.AttributeUsage int usage)298     public int getVolumeGroupIdForUsage(@AudioAttributes.AttributeUsage int usage)
299             throws CarNotConnectedException {
300         try {
301             return mService.getVolumeGroupIdForUsage(usage);
302         } catch (RemoteException e) {
303             Log.e(CarLibLog.TAG_CAR, "getVolumeGroupIdForUsage failed", e);
304             throw new CarNotConnectedException(e);
305         }
306     }
307 
308     /**
309      * Gets array of {@link AudioAttributes} usages for a given volume group id.
310      *
311      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
312      *
313      * @param groupId The volume group id whose associated audio usages is returned.
314      * @return Array of {@link AudioAttributes} usages for a given volume group id
315      */
316     @SystemApi
getUsagesForVolumeGroupId(int groupId)317     public @NonNull int[] getUsagesForVolumeGroupId(int groupId) throws CarNotConnectedException {
318         try {
319             return mService.getUsagesForVolumeGroupId(groupId);
320         } catch (RemoteException e) {
321             Log.e(CarLibLog.TAG_CAR, "getUsagesForVolumeGroupId failed", e);
322             throw new CarNotConnectedException(e);
323         }
324     }
325 
326     /**
327      * Register {@link ICarVolumeCallback} to receive the volume key events
328      *
329      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
330      *
331      * @param binder {@link IBinder} instance of {@link ICarVolumeCallback} to receive
332      *                              volume key event callbacks
333      * @throws CarNotConnectedException
334      */
335     @SystemApi
registerVolumeCallback(@onNull IBinder binder)336     public void registerVolumeCallback(@NonNull IBinder binder)
337             throws CarNotConnectedException {
338         try {
339             mService.registerVolumeCallback(binder);
340         } catch (RemoteException e) {
341             Log.e(CarLibLog.TAG_CAR, "registerVolumeCallback failed", e);
342             throw new CarNotConnectedException(e);
343         }
344     }
345 
346     /**
347      * Unregister {@link ICarVolumeCallback} from receiving volume key events
348      *
349      * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
350      *
351      * @param binder {@link IBinder} instance of {@link ICarVolumeCallback} to stop receiving
352      *                              volume key event callbacks
353      * @throws CarNotConnectedException
354      */
355     @SystemApi
unregisterVolumeCallback(@onNull IBinder binder)356     public void unregisterVolumeCallback(@NonNull IBinder binder)
357             throws CarNotConnectedException {
358         try {
359             mService.unregisterVolumeCallback(binder);
360         } catch (RemoteException e) {
361             Log.e(CarLibLog.TAG_CAR, "unregisterVolumeCallback failed", e);
362             throw new CarNotConnectedException(e);
363         }
364     }
365 
366     /** @hide */
367     @Override
onCarDisconnected()368     public void onCarDisconnected() {
369     }
370 
371     /** @hide */
CarAudioManager(IBinder service, Context context, Handler handler)372     public CarAudioManager(IBinder service, Context context, Handler handler) {
373         mContentResolver = context.getContentResolver();
374         mService = ICarAudio.Stub.asInterface(service);
375     }
376 }
377