Home | History | Annotate | Download | only in media
      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      */
     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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    368     public void onCarDisconnected() {
    369     }
    370 
    371     /** @hide */
    372     public CarAudioManager(IBinder service, Context context, Handler handler) {
    373         mContentResolver = context.getContentResolver();
    374         mService = ICarAudio.Stub.asInterface(service);
    375     }
    376 }
    377