New car OEM plugin services in Android 14 enable some car components to be configured. For audio specifically, three new plugin services are introduced, which enable OEMs to flexibly configure audio management on AAOS devices:
- Audio focus control
- Audio volume and mute control
- Audio Ducking control
Car plugin service architecture
The figure below provides an overview of the car services and their relationship to the OEM car service. Similar to the app processes and car service process, the OEM car service process occupies its own process space.
Car service starts the OEM car service by finding the component defined in
config_oemCarService
. If the config is empty, the OEM service does not exist
and no service is started. The component must extend
OemCarService.
The car audio service must overwrite the APIs for acquiring the car audio OEM
service:
public final class OemCarServiceImp extends OemCarService {
@Override
public OemCarAudioFocusService getOemAudioFocusService();
@Override
public OemCarAudioDuckingService getOemAudioDuckingService();
@Override
public OemCarAudioVolumeService getOemAudioVolumeService();
}
For
example, see
the reference test app defined in
packages/services/Car/tests/OemCarServiceTestApp
.
Even though the service is started by car service, it does not automatically
inherit the permissions available to car audio service. As such, any
permission required by OEM services should be acquired with the proper
mechanism. For example, see
packages/services/Car/data/etc/com.android.car.oemcarservice.testapp.xml
.
Car audio service with OEM service architecture
In AAOS, car audio service manages these actions:
- Audio routing
- Audio focus
- Audio ducking
- Volume and mute
Before Android 14, this behavior was largely static and could only be modified through settings, albeit for a very limited set of cases. Android 14 introduced a mechanism for car audio service to communicate with an OEM-defined component that manages:
- Audio focus
- Audio ducking
- Volume and mute
The figure below shows a simplified architecture for the car audio service and car OEM service. The car audio service defines different hooks that can call on the car OEM audio service to manage audio behavior. The latter occurs only if the corresponding OEM car audio service component is defined. Otherwise, the car audio service uses the default behavior.
To ensure that the car audio service and car OEM audio service are always in sync, for each call the car audio service passes the required parts of the current state of the audio stack to the car OEM audio service. For example, when the car audio service intercepts a request to evaluate audio focus, it passes the current state of the stack to the car OEM audio service. The current state includes the current focus holder and the current focus losers. Focus losers are focus requests that are still part of the stack but that have temporarily lost focus.
The car audio service must manage all audio activity in the car. If the car audio service does not manage some parts of the audio behavior, then the information exposed to the car OEM audio service is incomplete. For example, if an OEM overwrites the audio focus handling in the car service by registering their own audio focus policy, then the car audio service can't provide complete information to the car OEM audio service. This can affect the ability of the car OEM audio service to make decisions since it may lack information not visible to the car audio service.
To take actions, the car audio service calls the OEM car services. These calls are made across processes, which requires inter-process communication (IPC). IPC adds latency to each call. It's important to minimize latency in the OEM service.
Since car audio service calls to OEM service are blocking, the OEM service should not call the car audio service on direct API evaluations. Instead, the car audio service provides the necessary information so that calls between the two processes need only travel in one direction.
OEM car audio service definitions
OEM car audio focus service
Car audio service manages audio focus requests from apps by registering an audio policy focus listener. Car audio service has a mechanism to manage the focus behavior based on a static Interaction matrix. The matrix defines three different kind of interactions:
Concurrent interaction. Focus holders can maintain focus at the same time.
Exclusive interactions. Incoming focus request takes focus from the current focus holder.
Reject interaction. Incoming focus request rejected based on the current focus holder.
While this suffices for some automotive use cases, it does not fulfill all the
needs of interaction that may differ due to OEM requirements. For this we
introduce the OemCarAudioFocusService
:
public interface OEmCarAudioFocusService {
OemCarAuddioFocusResults evaluateAudioFocusRequest(
OemCarAudioFocusEvaluationRequest request);
void notifyAudioFocusChange(
List<AudioFocusEntry> holder,
List<AudioFocusEntry> losers, int zoneId);
}
The API evaluateAudioFocusRequest
is called from the car audio service anytime
there is a request for audio focus that needs to be evaluated, it is a two way
API that blocks for the results to return. The request contains information
about current state of the audio stack:
This information can be used to evaluate the newFocusRequest
compared to the
current focus holders in focusHolders
and the current focus losers in
focusLosers
. The API should return the results:
class OemCarAudioFocusResult {
int audioZoneId;
int audioFocusEvaluationResults;
AudioFocusEntry focusResult;
List<AudioFocusEntry> newLosers;
List<AudioFocusEntry> newlyBlocked;
}
This contains the information about actual evaluation results in
audioFocusEvaluationResults
, which indicates whether the current request has
been granted, delayed, or it has failed. Any changes to the current focus stack
should be set in newLosers
and newlyBlocked
entries, depending on the nature
of the stack change.
Where the newLosers
contains entries that were previously holding focus but
should now lose focus, either permanently or transiently. Permanent focus losers
will be further removed from the audio focus stack, and transient focus losers
will be moved to the current focus losers stack until they regain focus or are
abandoned from the original focus requester. Regardless, the focus listener for
the requests will receive a corresponding focus lost.
The newlyBlocked
list contains entries that were previously in the focus loser
list but now are blocked by the new entry. The block can be permanent or
transient, for permanent focus blocked the entry will be removed from the stack
and focus loss will be sent to the focus listeners. For transient focus loss,
the entry will remain in the focus losers stack but a new focus blocker will be
added to its list of blocker, no focus loss will be sent as one was previously
sent when it was first blocked. The request will finally be unblocked when all
current blockers are removed, or it will be removed from the stack if focus is
abandoned.
The second API, notifyAudioFocusChange
, is a one way which is called on every
audio focus request or abandon. The API is mostly used to inform the OEM service
about focus changes, which may affect the behavior of the OEM car audio service.
Guidelines for focus evaluation
In AAOS, audio focus is used to manage audio playback and to determine which app should adhere to provide an optimal experience for the user. As such, the OEM plugin service should take into account the following when managing an audio focus request:
Without any standing high priority audio focus (such as a phone call, emergency, or safety) apps should be able to gain audio focus either transiently or permanently.
While a media focus is active, apps requesting:
Call usage focus, should be able to receive focus either concurrently or exclusively.
Navigation usage focus, should be able to receive focus either concurrently or exclusively.
Assistant usage focus, should be able to receive focus either concurrently or exclusively.
While standing high priority audio focus (such as a phone call, emergency alert, or safety alert) apps are active, any incoming delayed audio focus request should be either granted or delayed as needed.
While the suggestions above are not exhaustive, they can help guarantee that apps requesting focus should be able to obtain focus when there are no active high priority sounds. Even while high priority sounds are active, delayed focus requests should still be respected and should be able to gain focus once the high priority sound stops.
OEM car volume service
The car audio service manages volume key events by either listening to volume adjustments from the audio system or by listening to volume key events directly from the car input service. In each case, the default behavior of the car audio service is to determine which volume group to change based on the active audio players and an audio context priority list.
We provide two volume priority lists. The first list considers all audio contexts in this order. The list is presented in descending order, the highest priority at the top and the lowest priority at the bottom. For example, if navigation audio and music audio are both active at the same time, then navigation volume is changed during a volume key event.
- Navigation
- Call
- Music
- Announcement
- Voice command
- Call ring
- System sound
- Safety
- Alarm
- Notification
- Vehicle status
- Emergency
To make the volume key event management less complex, car audio service has a second priority list of audio context:
- Call
- Media
- Announcement
- Voice command
This list is also presented in descending order. The purpose of this secon list is to allow more common sounds to be changed through key events. Uncommon, perhaps sounds of a shorter duration, can be managed through the audio settings UI only.
The actual version of the volume can be set with the
audioVolumeAdjustmentContextsVersion
configuration. The configuration can be
set to either 1
or 2
(2
is the default).
To provide more flexibility to volume management,
OemCarAudioVolumeService
is introduced in Android 14:
public interface OemCarAudioVolumeService {
OemCarvolumeChangeInfo getSuggestedGroupForVolumeChange(
OemCarAudioVolumeRequest request, int volumeAdjustment);
}
The OEM car audio volume service has a single method, which takes in a
volumeAdjustment
and an OemCarAudioVolumeRequest
:
class OemCarAudioVolumeRequest {
int audioZoneId;
int callState;
List<AudioAttributes> activePlaybackAttributes;
List<AudioAttributes> duckedAttributes;
List<CarVolumeGroupInfo> volumeGroupState;
}
The request’s activePlaybackAttributes
has the active audio attributes. The
duckedAttributes
are all currently ducked audio attributes. The
volumeGroupState
has the current state of the volumes group. The request
represents the current state of the audio stack and can be used to determine
which volume group should be changed. The results should be returned in
OemCarVolumeChangeInfo
:
class OemCarVolumeChangeInfo {
boolean change;
CarVolumeGroupInfo volumeGroupChanged;
}
The change
boolean indicates if any volume has changed, true
indicates that
there is a change and the volume group should be updated. The
volumeGroupChanged
is the actual volume group that should be changed. This
group should be changed according to the original volumeAdjustment
parameter
passed to the API. For example, if the results indicate that the navigation
volume group should be muted, then the boolean would be true
and the returned
volume group should be that for navigation.
OEM car ducking service
Car audio service manages audio ducking by monitoring audio focus changes and
sending a signal to the AudioControl
HAL about which audio devices to duck.
When the focus changes, all the active focus holders are evaluated to determine
which should be ducked based on this set of static ducking
rules:
- Emergency sounds duck everything except call sounds
- Safety ducks everything except emergency sounds
- Navigation ducks everything except safety and emergency sounds
- Call ducks everything except safety, emergency, and navigation sounds
- Voice ducks call ring sounds
- Music and announcements should be ducked by everything
These rules are not exhaustive and OEMs remain responsible for determining
how sounds should be ducked based on these guidelines. OEMs can control these
recommendations more actively based on the available requirements. The
OemCarDuckingService
is introduced in Android 14:
class OemCarAudioDuckingService {
List<AudioAttributes> evaluateAttributesToDuck(
OemCarAudioVolumeRequest request);
}
This API is called from the car audio service on audio focus changes. It re-uses
the OemCarAudioVolumeRequest
introduced in
OEM car volume service, and contains the relevant
information to make the decision about which attributes to duck. The list of
audio attributes to duck from the API is compared to the current audio state:
Audio attribute currently ducked:
- On list, continues to be ducked
- Not on list, ducking turned off
Audio attribute not currently ducked:
- On list, ducked
- Not on list, ducking turned off
The car audio service then determines which audio output devices the audio attributes belong to and adds them to the ducked audio output device list or the unducked audio devices list, respectively. This is ultimately sent to the AudioControl HAL to perform the required ducking at the hardware level.
The figure below shows a simplified sequence diagram of the audio ducking control for a focus request when the OEM ducking service is used:
The sequence starts when an app requests
Manage audio focus
through public audio manager APIs. The request is forwarded to the car audio
service to determine the results. When audio focus is decided, the audio ducking
is evaluated by the car audio service calling the OemCarAudioDuckingService
to
evaluate which audio attributes should be ducked. Once the results are returned
from the evaluateAttributesToDuck
API, the audio devices to duck are computed,
and finally the information is sent to the AudioControl
to apply ducking
to the audio hardware.
OEM car audio service reference implementation
AAOS provides a reference implementation of the OEM car service in
packages/services/Car/tests/OemCarServiceTestApp
, which implements the
OemCarService
, along with OemCarAudioFocusService
,
OemCarAudioDuckingService
, and the OemCarAudioVolumeService
. For the latter,
each service uses and XML file to load a static behavior. For example,
OemCarAudioFocusServiceImp
loads the oem_focus_config.xml
, which
contains an interaction matrix. The matrix is used to evaluate the focus request
when the evaluateAudioFocusRequest
is called.
Reference test app debugging
The OEM car service test app is part of the AOSP source code. OEMs can make
changes according to their needs. For debugging, use the config_oemCarService
configuration to enable the test app.
<!-- This is the component name for the OEM customization service. OEM can choose to implement
this service to customize car service behavior for different policies. If OEMs choose to
implement it, they have to implement a service extending OemCarService exposed by car-lib,
and implement the required component services.
If the component name is invalid, CarService would not connect to any OEM service.
Component name can not be a third party package. It should be pre-installed -->
<string name="config_oemCarService" translatable="false">
com.android.car.oemcarservice.testapp/.OemCarServiceImpl
</string>
To verify the OEM car service uses the car service dump
command for the
OEM service:
adb shell dumpsys car_service --oem-service
The results could be similar to the output below:
***CarOemProxyService dump***
mIsFeatureEnabled: true
mIsOemServiceBound: true
mIsOemServiceReady: true
mIsOemServiceConnected: true
mInitComplete: true
OEM_CAR_SERVICE_CONNECTED_TIMEOUT_MS: 5000
OEM_CAR_SERVICE_READY_TIMEOUT_MS: 5000
mComponentName: com.android.car.oemcarservice.testapp/.OemCarServiceImpl
Each boolean in each batch of dump
info determines the state of the feature
and service. For example, the dump info mIsOemServiceReady
specifies if the
service is ready to be used, where true
indicates it is ready and false
indicates it is not ready.