blob: 7257255c12c7ca9be48143ed3062ae617ae91e4c [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.car.media;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.car.CarLibLog;
import android.car.CarManagerBase;
import android.car.CarNotConnectedException;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.media.AudioAttributes;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
/**
* APIs for handling car specific audio stuff.
*/
public final class CarAudioManager implements CarManagerBase {
// The trailing slash forms a directory-liked hierarchy and
// allows listening for both GROUP/MEDIA and GROUP/NAVIGATION.
private static final String VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX = "android.car.VOLUME_GROUP/";
/**
* @param groupId The volume group id
* @return Key to persist volume index for volume group in {@link Settings.Global}
*/
public static String getVolumeSettingsKeyForGroup(int groupId) {
return VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX + groupId;
}
/**
* Key to persist master mute state in {@link Settings.Global}
*
* @hide
*/
public static final String VOLUME_SETTINGS_KEY_MASTER_MUTE = "android.car.MASTER_MUTE";
private final ContentResolver mContentResolver;
private final ICarAudio mService;
/**
* Registers a {@link ContentObserver} to listen for volume group changes.
* Note that this observer is valid for bus based car audio stack only.
*
* {@link ContentObserver#onChange(boolean)} will be called on every group volume change.
*
* @param observer The {@link ContentObserver} instance to register, non-null
*/
@SystemApi
public void registerVolumeChangeObserver(@NonNull ContentObserver observer) {
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX),
true, observer);
}
/**
* Unregisters the {@link ContentObserver} which listens for volume group changes.
*
* @param observer The {@link ContentObserver} instance to unregister, non-null
*/
@SystemApi
public void unregisterVolumeChangeObserver(@NonNull ContentObserver observer) {
mContentResolver.unregisterContentObserver(observer);
}
/**
* Sets the volume index for a volume group.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param groupId The volume group id whose volume index should be set.
* @param index The volume index to set. See
* {@link #getGroupMaxVolume(int)} for the largest valid value.
* @param flags One or more flags (e.g., {@link android.media.AudioManager#FLAG_SHOW_UI},
* {@link android.media.AudioManager#FLAG_PLAY_SOUND})
*/
@SystemApi
public void setGroupVolume(int groupId, int index, int flags) throws CarNotConnectedException {
try {
mService.setGroupVolume(groupId, index, flags);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "setGroupVolume failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Returns the maximum volume index for a volume group.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param groupId The volume group id whose maximum volume index is returned.
* @return The maximum valid volume index for the given group.
*/
@SystemApi
public int getGroupMaxVolume(int groupId) throws CarNotConnectedException {
try {
return mService.getGroupMaxVolume(groupId);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "getUsageMaxVolume failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Returns the minimum volume index for a volume group.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param groupId The volume group id whose minimum volume index is returned.
* @return The minimum valid volume index for the given group, non-negative
*/
@SystemApi
public int getGroupMinVolume(int groupId) throws CarNotConnectedException {
try {
return mService.getGroupMinVolume(groupId);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "getUsageMinVolume failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Returns the current volume index for a volume group.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param groupId The volume group id whose volume index is returned.
* @return The current volume index for the given group.
*
* @see #getGroupMaxVolume(int)
* @see #setGroupVolume(int, int, int)
*/
@SystemApi
public int getGroupVolume(int groupId) throws CarNotConnectedException {
try {
return mService.getGroupVolume(groupId);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "getUsageVolume failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Adjust the relative volume in the front vs back of the vehicle cabin.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param value in the range -1.0 to 1.0 for fully toward the back through
* fully toward the front. 0.0 means evenly balanced.
*
* @see #setBalanceTowardRight(float)
*/
@SystemApi
public void setFadeTowardFront(float value) throws CarNotConnectedException {
try {
mService.setFadeTowardFront(value);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "setFadeTowardFront failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Adjust the relative volume on the left vs right side of the vehicle cabin.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param value in the range -1.0 to 1.0 for fully toward the left through
* fully toward the right. 0.0 means evenly balanced.
*
* @see #setFadeTowardFront(float)
*/
@SystemApi
public void setBalanceTowardRight(float value) throws CarNotConnectedException {
try {
mService.setBalanceTowardRight(value);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "setBalanceTowardRight failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Queries the system configuration in order to report the available, non-microphone audio
* input devices.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
*
* @return An array of strings representing the available input ports.
* Each port is identified by it's "address" tag in the audioPolicyConfiguration xml file.
* Empty array if we find nothing.
*
* @see #createAudioPatch(String, int, int)
* @see #releaseAudioPatch(CarAudioPatchHandle)
*/
@SystemApi
public @NonNull String[] getExternalSources() throws CarNotConnectedException {
try {
return mService.getExternalSources();
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "getExternalSources failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Given an input port identified by getExternalSources(), request that it's audio signal
* be routed below the HAL to the output port associated with the given usage. For example,
* The output of a tuner might be routed directly to the output buss associated with
* AudioAttributes.USAGE_MEDIA while the tuner is playing.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
*
* @param sourceAddress the input port name obtained from getExternalSources().
* @param usage the type of audio represented by this source (usually USAGE_MEDIA).
* @param gainInMillibels How many steps above the minimum value defined for the source port to
* set the gain when creating the patch.
* This may be used for source balancing without affecting the user
* controlled volumes applied to the destination ports. A value of
* 0 indicates no gain change is requested.
* @return A handle for the created patch which can be used to later remove it.
*
* @see #getExternalSources()
* @see #releaseAudioPatch(CarAudioPatchHandle)
*/
@SystemApi
public CarAudioPatchHandle createAudioPatch(String sourceAddress,
@AudioAttributes.AttributeUsage int usage, int gainInMillibels)
throws CarNotConnectedException {
try {
return mService.createAudioPatch(sourceAddress, usage, gainInMillibels);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "createAudioPatch failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Removes the association between an input port and an output port identified by the provided
* handle.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
*
* @param patch CarAudioPatchHandle returned from createAudioPatch().
*
* @see #getExternalSources()
* @see #createAudioPatch(String, int, int)
*/
@SystemApi
public void releaseAudioPatch(CarAudioPatchHandle patch) throws CarNotConnectedException {
try {
mService.releaseAudioPatch(patch);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "releaseAudioPatch failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Gets the count of available volume groups in the system.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @return Count of volume groups
*/
@SystemApi
public int getVolumeGroupCount() throws CarNotConnectedException {
try {
return mService.getVolumeGroupCount();
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "getVolumeGroupCount failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Gets the volume group id for a given {@link AudioAttributes} usage.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param usage The {@link AudioAttributes} usage to get a volume group from.
* @return The volume group id where the usage belongs to
*/
@SystemApi
public int getVolumeGroupIdForUsage(@AudioAttributes.AttributeUsage int usage)
throws CarNotConnectedException {
try {
return mService.getVolumeGroupIdForUsage(usage);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "getVolumeGroupIdForUsage failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Gets array of {@link AudioAttributes} usages for a given volume group id.
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param groupId The volume group id whose associated audio usages is returned.
* @return Array of {@link AudioAttributes} usages for a given volume group id
*/
@SystemApi
public @NonNull int[] getUsagesForVolumeGroupId(int groupId) throws CarNotConnectedException {
try {
return mService.getUsagesForVolumeGroupId(groupId);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "getUsagesForVolumeGroupId failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Register {@link ICarVolumeCallback} to receive the volume key events
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param binder {@link IBinder} instance of {@link ICarVolumeCallback} to receive
* volume key event callbacks
* @throws CarNotConnectedException
*/
@SystemApi
public void registerVolumeCallback(@NonNull IBinder binder)
throws CarNotConnectedException {
try {
mService.registerVolumeCallback(binder);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "registerVolumeCallback failed", e);
throw new CarNotConnectedException(e);
}
}
/**
* Unregister {@link ICarVolumeCallback} from receiving volume key events
*
* Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
*
* @param binder {@link IBinder} instance of {@link ICarVolumeCallback} to stop receiving
* volume key event callbacks
* @throws CarNotConnectedException
*/
@SystemApi
public void unregisterVolumeCallback(@NonNull IBinder binder)
throws CarNotConnectedException {
try {
mService.unregisterVolumeCallback(binder);
} catch (RemoteException e) {
Log.e(CarLibLog.TAG_CAR, "unregisterVolumeCallback failed", e);
throw new CarNotConnectedException(e);
}
}
/** @hide */
@Override
public void onCarDisconnected() {
}
/** @hide */
public CarAudioManager(IBinder service, Context context, Handler handler) {
mContentResolver = context.getContentResolver();
mService = ICarAudio.Stub.asInterface(service);
}
}