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.IntDef;
     19 import android.annotation.Nullable;
     20 import android.annotation.SystemApi;
     21 import android.car.CarLibLog;
     22 import android.car.CarNotConnectedException;
     23 import android.content.Context;
     24 import android.media.AudioAttributes;
     25 import android.media.AudioManager;
     26 import android.media.AudioManager.OnAudioFocusChangeListener;
     27 import android.media.IVolumeController;
     28 import android.os.Handler;
     29 import android.os.IBinder;
     30 import android.os.RemoteException;
     31 import android.car.CarManagerBase;
     32 import android.util.Log;
     33 
     34 import java.lang.annotation.Retention;
     35 import java.lang.annotation.RetentionPolicy;
     36 import java.lang.ref.WeakReference;
     37 
     38 /**
     39  * APIs for handling car specific audio stuffs.
     40  */
     41 public final class CarAudioManager implements CarManagerBase {
     42 
     43     /**
     44      * Audio usage for unspecified type.
     45      */
     46     public static final int CAR_AUDIO_USAGE_DEFAULT = 0;
     47     /**
     48      * Audio usage for playing music.
     49      */
     50     public static final int CAR_AUDIO_USAGE_MUSIC = 1;
     51     /**
     52      * Audio usage for H/W radio.
     53      */
     54     public static final int CAR_AUDIO_USAGE_RADIO = 2;
     55     /**
     56      * Audio usage for playing navigation guidance.
     57      */
     58     public static final int CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE = 3;
     59     /**
     60      * Audio usage for voice call
     61      */
     62     public static final int CAR_AUDIO_USAGE_VOICE_CALL = 4;
     63     /**
     64      * Audio usage for voice search or voice command.
     65      */
     66     public static final int CAR_AUDIO_USAGE_VOICE_COMMAND = 5;
     67     /**
     68      * Audio usage for playing alarm.
     69      */
     70     public static final int CAR_AUDIO_USAGE_ALARM = 6;
     71     /**
     72      * Audio usage for notification sound.
     73      */
     74     public static final int CAR_AUDIO_USAGE_NOTIFICATION = 7;
     75     /**
     76      * Audio usage for system sound like UI feedback.
     77      */
     78     public static final int CAR_AUDIO_USAGE_SYSTEM_SOUND = 8;
     79     /**
     80      * Audio usage for playing safety alert.
     81      */
     82     public static final int CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT = 9;
     83     /**
     84      * Audio usage for external audio usage.
     85      * @hide
     86      */
     87     public static final int CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE = 10;
     88 
     89     /** @hide */
     90     public static final int CAR_AUDIO_USAGE_MAX = CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE;
     91 
     92     /** @hide */
     93     @IntDef({CAR_AUDIO_USAGE_DEFAULT, CAR_AUDIO_USAGE_MUSIC, CAR_AUDIO_USAGE_RADIO,
     94         CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE, CAR_AUDIO_USAGE_VOICE_CALL,
     95         CAR_AUDIO_USAGE_VOICE_COMMAND, CAR_AUDIO_USAGE_ALARM, CAR_AUDIO_USAGE_NOTIFICATION,
     96         CAR_AUDIO_USAGE_SYSTEM_SOUND, CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT,
     97         CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE})
     98     @Retention(RetentionPolicy.SOURCE)
     99     public @interface CarAudioUsage {}
    100 
    101     /** @hide */
    102     public static final String CAR_RADIO_TYPE_AM_FM = "RADIO_AM_FM";
    103     /** @hide */
    104     public static final String CAR_RADIO_TYPE_AM_FM_HD = "RADIO_AM_FM_HD";
    105     /** @hide */
    106     public static final String CAR_RADIO_TYPE_DAB = "RADIO_DAB";
    107     /** @hide */
    108     public static final String CAR_RADIO_TYPE_SATELLITE = "RADIO_SATELLITE";
    109 
    110     /** @hide */
    111     public static final String CAR_EXTERNAL_SOURCE_TYPE_CD_DVD = "CD_DVD";
    112     /** @hide */
    113     public static final String CAR_EXTERNAL_SOURCE_TYPE_AUX_IN0 = "AUX_IN0";
    114     /** @hide */
    115     public static final String CAR_EXTERNAL_SOURCE_TYPE_AUX_IN1 = "AUX_IN1";
    116     /** @hide */
    117     public static final String CAR_EXTERNAL_SOURCE_TYPE_EXT_NAV_GUIDANCE = "EXT_NAV_GUIDANCE";
    118     /** @hide */
    119     public static final String CAR_EXTERNAL_SOURCE_TYPE_EXT_VOICE_CALL = "EXT_VOICE_CALL";
    120     /** @hide */
    121     public static final String CAR_EXTERNAL_SOURCE_TYPE_EXT_VOICE_COMMAND = "EXT_VOICE_COMMAND";
    122     /** @hide */
    123     public static final String CAR_EXTERNAL_SOURCE_TYPE_EXT_SAFETY_ALERT = "EXT_SAFETY_ALERT";
    124 
    125     private final ICarAudio mService;
    126     private final AudioManager mAudioManager;
    127     private final Handler mHandler;
    128 
    129     private ParameterChangeCallback mParameterChangeCallback;
    130     private OnParameterChangeListener mOnParameterChangeListener;
    131 
    132     /**
    133      * Get {@link AudioAttributes} relevant for the given usage in car.
    134      * @param carUsage
    135      * @return
    136      */
    137     public AudioAttributes getAudioAttributesForCarUsage(@CarAudioUsage int carUsage)
    138             throws CarNotConnectedException {
    139         try {
    140             return mService.getAudioAttributesForCarUsage(carUsage);
    141         } catch (RemoteException e) {
    142             throw new CarNotConnectedException();
    143         }
    144     }
    145 
    146     /**
    147      * Get AudioAttributes for radio. This is necessary when there are multiple types of radio
    148      * in system.
    149      *
    150      * @param radioType String specifying the desired radio type. Should use only what is listed in
    151      *        {@link #getSupportedRadioTypes()}.
    152      * @return
    153      * @throws IllegalArgumentException If not supported type is passed.
    154      *
    155      * @hide
    156      */
    157     public AudioAttributes getAudioAttributesForRadio(String radioType)
    158             throws CarNotConnectedException, IllegalArgumentException {
    159         try {
    160             return mService.getAudioAttributesForRadio(radioType);
    161         } catch (RemoteException e) {
    162             throw new CarNotConnectedException();
    163         }
    164     }
    165 
    166     /**
    167      * Get AudioAttributes for external audio source.
    168      *
    169      * @param externalSourceType String specifying the desired source type. Should use only what is
    170      *        listed in {@link #getSupportedExternalSourceTypes()}.
    171      * @return
    172      * @throws IllegalArgumentException If not supported type is passed.
    173      *
    174      * @hide
    175      */
    176     public AudioAttributes getAudioAttributesForExternalSource(String externalSourceType)
    177             throws CarNotConnectedException, IllegalArgumentException {
    178         try {
    179             return mService.getAudioAttributesForExternalSource(externalSourceType);
    180         } catch (RemoteException e) {
    181             throw new CarNotConnectedException();
    182         }
    183     }
    184 
    185     /**
    186      * List all supported external audio sources.
    187      *
    188      * @return
    189      *
    190      * @hide
    191      */
    192     public String[] getSupportedExternalSourceTypes() throws CarNotConnectedException {
    193         try {
    194             return mService.getSupportedExternalSourceTypes();
    195         } catch (RemoteException e) {
    196             throw new CarNotConnectedException();
    197         }
    198     }
    199 
    200     /**
    201      * List all supported radio sources.
    202      *
    203      * @return
    204      *
    205      * @hide
    206      */
    207     public String[] getSupportedRadioTypes() throws CarNotConnectedException {
    208         try {
    209             return mService.getSupportedRadioTypes();
    210         } catch (RemoteException e) {
    211             throw new CarNotConnectedException();
    212         }
    213     }
    214 
    215     /**
    216      * Request audio focus.
    217      * Send a request to obtain the audio focus.
    218      * @param l
    219      * @param requestAttributes
    220      * @param durationHint
    221      * @param flags
    222      */
    223     public int requestAudioFocus(OnAudioFocusChangeListener l,
    224                                  AudioAttributes requestAttributes,
    225                                  int durationHint,
    226                                  int flags)
    227                                          throws CarNotConnectedException, IllegalArgumentException {
    228         return mAudioManager.requestAudioFocus(l, requestAttributes, durationHint, flags);
    229     }
    230 
    231     /**
    232      * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
    233      * @param l
    234      * @param aa
    235      */
    236     public void abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
    237         mAudioManager.abandonAudioFocus(l, aa);
    238     }
    239 
    240     /**
    241      * Sets the volume index for a particular stream.
    242      *
    243      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
    244      *
    245      * @param streamType The stream whose volume index should be set.
    246      * @param index The volume index to set. See
    247      *            {@link #getStreamMaxVolume(int)} for the largest valid value.
    248      * @param flags One or more flags (e.g., {@link android.media.AudioManager#FLAG_SHOW_UI},
    249      *              {@link android.media.AudioManager#FLAG_PLAY_SOUND})
    250      */
    251     @SystemApi
    252     public void setStreamVolume(int streamType, int index, int flags)
    253             throws CarNotConnectedException {
    254         try {
    255             mService.setStreamVolume(streamType, index, flags);
    256         } catch (RemoteException e) {
    257             Log.e(CarLibLog.TAG_CAR, "setStreamVolume failed", e);
    258             throw new CarNotConnectedException(e);
    259         }
    260     }
    261 
    262     /**
    263      * Registers a global volume controller interface.
    264      *
    265      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
    266      *
    267      * @hide
    268      */
    269     @SystemApi
    270     public void setVolumeController(IVolumeController controller)
    271             throws CarNotConnectedException {
    272         try {
    273             mService.setVolumeController(controller);
    274         } catch (RemoteException e) {
    275             Log.e(CarLibLog.TAG_CAR, "setVolumeController failed", e);
    276             throw new CarNotConnectedException(e);
    277         }
    278     }
    279 
    280     /**
    281      * Returns the maximum volume index for a particular stream.
    282      *
    283      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
    284      *
    285      * @param stream The stream type whose maximum volume index is returned.
    286      * @return The maximum valid volume index for the stream.
    287      */
    288     @SystemApi
    289     public int getStreamMaxVolume(int stream) throws CarNotConnectedException {
    290         try {
    291             return mService.getStreamMaxVolume(stream);
    292         } catch (RemoteException e) {
    293             Log.e(CarLibLog.TAG_CAR, "getStreamMaxVolume failed", e);
    294             throw new CarNotConnectedException(e);
    295         }
    296     }
    297 
    298     /**
    299      * Returns the minimum volume index for a particular stream.
    300      *
    301      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
    302      *
    303      * @param stream The stream type whose maximum volume index is returned.
    304      * @return The maximum valid volume index for the stream.
    305      */
    306     @SystemApi
    307     public int getStreamMinVolume(int stream) throws CarNotConnectedException {
    308         try {
    309             return mService.getStreamMinVolume(stream);
    310         } catch (RemoteException e) {
    311             Log.e(CarLibLog.TAG_CAR, "getStreamMaxVolume failed", e);
    312             throw new CarNotConnectedException(e);
    313         }
    314     }
    315 
    316     /**
    317      * Returns the current volume index for a particular stream.
    318      *
    319      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
    320      *
    321      * @param stream The stream type whose volume index is returned.
    322      * @return The current volume index for the stream.
    323      *
    324      * @see #getStreamMaxVolume(int)
    325      * @see #setStreamVolume(int, int, int)
    326      */
    327     @SystemApi
    328     public int getStreamVolume(int stream) throws CarNotConnectedException {
    329         try {
    330             return mService.getStreamVolume(stream);
    331         } catch (RemoteException e) {
    332             Log.e(CarLibLog.TAG_CAR, "getStreamVolume failed", e);
    333             throw new CarNotConnectedException(e);
    334         }
    335     }
    336 
    337     /**
    338      * Check if media audio is muted or not. This will include music and radio. Any application
    339      * taking audio focus for media stream will get it out of mute state.
    340      *
    341      * @return true if media is muted.
    342      * @throws CarNotConnectedException if the connection to the car service has been lost.
    343      * @hide
    344      */
    345     @SystemApi
    346     public boolean isMediaMuted() throws CarNotConnectedException {
    347         try {
    348             return mService.isMediaMuted();
    349         } catch (RemoteException e) {
    350             Log.e(CarLibLog.TAG_CAR, "isMediaMuted failed", e);
    351             throw new CarNotConnectedException(e);
    352         }
    353     }
    354 
    355     /**
    356      * Mute or unmute media stream including radio. This can involve audio focus change to stop
    357      * whatever app holding audio focus now. If requester is currently holding audio focus,
    358      * it will get LOSS_TRANSIENT focus loss.
    359      * This API requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
    360      *
    361      * @param mute
    362      * @return Mute state of system after the request. Note that mute request can fail if there
    363      *         is higher priority audio already being played like phone call.
    364      * @throws CarNotConnectedException if the connection to the car service has been lost.
    365      * @hide
    366      */
    367     @SystemApi
    368     public boolean setMediaMute(boolean mute) throws CarNotConnectedException {
    369         try {
    370             return mService.setMediaMute(mute);
    371         } catch (RemoteException e) {
    372             Log.e(CarLibLog.TAG_CAR, "setMediaMute failed", e);
    373             throw new CarNotConnectedException(e);
    374         }
    375     }
    376 
    377     /**
    378      * Listener to monitor audio parameter changes.
    379      * @hide
    380      */
    381     public interface OnParameterChangeListener {
    382         /**
    383          * Parameter changed.
    384          * @param parameters Have format of key1=value1;key2=value2;...
    385          */
    386         void onParameterChange(String parameters);
    387     }
    388 
    389     /**
    390      * Return array of keys supported in this system.
    391      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
    392      * The list is static and will not change.
    393      * @return null if there is no audio parameters supported.
    394      * @throws CarNotConnectedException
    395      *
    396      * @hide
    397      */
    398     public @Nullable String[] getParameterKeys() throws CarNotConnectedException {
    399         try {
    400             return mService.getParameterKeys();
    401         } catch (RemoteException e) {
    402             Log.e(CarLibLog.TAG_CAR, "getParameterKeys failed", e);
    403             throw new CarNotConnectedException(e);
    404         }
    405     }
    406 
    407     /**
    408      * Set car specific audio parameters.
    409      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
    410      * Only keys listed from {@link #getParameterKeys()} should be used.
    411      * @param parameters has format of key1=value1;key2=value2;...
    412      * @throws CarNotConnectedException
    413      *
    414      * @hide
    415      */
    416     public void setParameters(String parameters) throws CarNotConnectedException {
    417         try {
    418             mService.setParameters(parameters);
    419         } catch (RemoteException e) {
    420             Log.e(CarLibLog.TAG_CAR, "setParameters failed", e);
    421             throw new CarNotConnectedException(e);
    422         }
    423     }
    424 
    425     /**
    426      * Get parameters for the key passed.
    427      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
    428      * Only keys listed from {@link #getParameterKeys()} should be used.
    429      * @param keys Keys to get value. Format is key1;key2;...
    430      * @return Parameters in format of key1=value1;key2=value2;...
    431      * @throws CarNotConnectedException
    432      *
    433      * @hide
    434      */
    435     public String getParameters(String keys) throws CarNotConnectedException {
    436         try {
    437             return mService.getParameters(keys);
    438         } catch (RemoteException e) {
    439             Log.e(CarLibLog.TAG_CAR, "getParameters failed", e);
    440             throw new CarNotConnectedException(e);
    441         }
    442     }
    443 
    444     /**
    445      * Set listener to monitor audio parameter changes.
    446      * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
    447      * @param listener Non-null listener will start monitoring. null listener will stop listening.
    448      * @throws CarNotConnectedException
    449      *
    450      * @hide
    451      */
    452     public void setOnParameterChangeListener(OnParameterChangeListener listener)
    453             throws CarNotConnectedException {
    454         ParameterChangeCallback oldCb = null;
    455         ParameterChangeCallback newCb = null;
    456         synchronized (this) {
    457             if (listener != null) {
    458                 if (mParameterChangeCallback != null) {
    459                     oldCb = mParameterChangeCallback;
    460                 }
    461                 newCb = new ParameterChangeCallback(this);
    462             }
    463             mParameterChangeCallback = newCb;
    464             mOnParameterChangeListener = listener;
    465         }
    466         try {
    467             if (oldCb != null) {
    468                 mService.unregisterOnParameterChangeListener(oldCb);
    469             }
    470             if (newCb != null) {
    471                 mService.registerOnParameterChangeListener(newCb);
    472             }
    473         } catch (RemoteException e) {
    474             Log.e(CarLibLog.TAG_CAR, "setOnParameterChangeListener failed", e);
    475             throw new CarNotConnectedException(e);
    476         }
    477     }
    478 
    479     /** @hide */
    480     @Override
    481     public void onCarDisconnected() {
    482     }
    483 
    484     /** @hide */
    485     public CarAudioManager(IBinder service, Context context, Handler handler) {
    486         mService = ICarAudio.Stub.asInterface(service);
    487         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    488         mHandler = handler;
    489     }
    490 
    491     private AudioAttributes createAudioAttributes(int contentType, int usage) {
    492         AudioAttributes.Builder builder = new AudioAttributes.Builder();
    493         return builder.setContentType(contentType).setUsage(usage).build();
    494     }
    495 
    496     private static class ParameterChangeCallback extends ICarAudioCallback.Stub {
    497 
    498         private final WeakReference<CarAudioManager> mManager;
    499 
    500         private ParameterChangeCallback(CarAudioManager manager) {
    501             mManager = new WeakReference<>(manager);
    502         }
    503 
    504         @Override
    505         public void onParameterChange(final String params) {
    506             CarAudioManager manager = mManager.get();
    507             if (manager == null) {
    508                 return;
    509             }
    510             final OnParameterChangeListener listener = manager.mOnParameterChangeListener;
    511             if (listener == null) {
    512                 return;
    513             }
    514             manager.mHandler.post(new Runnable() {
    515                 @Override
    516                 public void run() {
    517                     listener.onParameterChange(params);
    518                 }
    519             });
    520         }
    521     }
    522 }
    523