• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.car.audio.hal;
18 
19 import static android.car.builtin.media.AudioManagerHelper.usageToString;
20 import static android.car.builtin.media.AudioManagerHelper.usageToXsdString;
21 import static android.car.builtin.media.AudioManagerHelper.xsdStringToUsage;
22 
23 import static com.android.car.audio.CarHalAudioUtils.usageToMetadata;
24 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
25 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
26 
27 import static java.util.Collections.EMPTY_LIST;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.car.builtin.os.ServiceManagerHelper;
32 import android.car.builtin.util.Slogf;
33 import android.car.feature.Flags;
34 import android.hardware.audio.common.PlaybackTrackMetadata;
35 import android.hardware.automotive.audiocontrol.AudioDeviceConfiguration;
36 import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
37 import android.hardware.automotive.audiocontrol.AudioZone;
38 import android.hardware.automotive.audiocontrol.DuckingInfo;
39 import android.hardware.automotive.audiocontrol.IAudioControl;
40 import android.hardware.automotive.audiocontrol.IAudioGainCallback;
41 import android.hardware.automotive.audiocontrol.IFocusListener;
42 import android.hardware.automotive.audiocontrol.IModuleChangeCallback;
43 import android.hardware.automotive.audiocontrol.MutingInfo;
44 import android.hardware.automotive.audiocontrol.RoutingDeviceConfiguration;
45 import android.media.audio.common.AudioPort;
46 import android.os.IBinder;
47 import android.os.RemoteException;
48 import android.util.Log;
49 
50 import com.android.car.CarLog;
51 import com.android.car.audio.CarAudioGainConfigInfo;
52 import com.android.car.audio.CarDuckingInfo;
53 import com.android.car.audio.CarHalAudioUtils;
54 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
55 import com.android.car.internal.annotation.AttributeUsage;
56 import com.android.car.internal.util.IndentingPrintWriter;
57 import com.android.internal.util.Preconditions;
58 
59 import java.util.ArrayList;
60 import java.util.List;
61 import java.util.Objects;
62 import java.util.concurrent.Executor;
63 import java.util.concurrent.Executors;
64 
65 /** Wrapper for AIDL interface for AudioControl HAL */
66 public final class AudioControlWrapperAidl implements AudioControlWrapper, IBinder.DeathRecipient {
67     static final String TAG = CarLog.tagFor(AudioControlWrapperAidl.class);
68 
69     private static final String AUDIO_CONTROL_SERVICE =
70             "android.hardware.automotive.audiocontrol.IAudioControl/default";
71 
72     private static final int AIDL_AUDIO_CONTROL_VERSION_1 = 1;
73     private static final int AIDL_AUDIO_CONTROL_VERSION_2 = 2;
74     private static final int AIDL_AUDIO_CONTROL_VERSION_3 = 3;
75     private static final int AIDL_AUDIO_CONTROL_VERSION_4 = 4;
76     private static final int AIDL_AUDIO_CONTROL_VERSION_5 = 5;
77 
78     private IBinder mBinder;
79     private IAudioControl mAudioControl;
80     private boolean mListenerRegistered = false;
81     private boolean mGainCallbackRegistered = false;
82     private boolean mModuleChangeCallbackRegistered;
83 
84     private AudioControlDeathRecipient mDeathRecipient;
85 
86     private Executor mExecutor = Executors.newSingleThreadExecutor();
87 
getService()88     public static @Nullable IBinder getService() {
89         return ServiceManagerHelper.waitForDeclaredService(AUDIO_CONTROL_SERVICE);
90     }
91 
AudioControlWrapperAidl(IBinder binder)92     public AudioControlWrapperAidl(IBinder binder) {
93         mBinder = Objects.requireNonNull(binder);
94         mAudioControl = IAudioControl.Stub.asInterface(binder);
95     }
96 
97     @Override
98     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
unregisterFocusListener()99     public void unregisterFocusListener() {
100         // Focus listener will be unregistered by HAL automatically
101     }
102 
103     @Override
supportsFeature(int feature)104     public boolean supportsFeature(int feature) {
105         switch (feature) {
106             case AUDIOCONTROL_FEATURE_AUDIO_FOCUS:
107             case AUDIOCONTROL_FEATURE_AUDIO_DUCKING:
108             case AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING:
109                 return true;
110             case AUDIOCONTROL_FEATURE_AUDIO_FOCUS_WITH_METADATA:
111             case AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK:
112                 try {
113                     return mAudioControl.getInterfaceVersion() > AIDL_AUDIO_CONTROL_VERSION_1;
114                 } catch (RemoteException e) {
115                     Slogf.w("supportsFeature Failed to get version for feature: " + feature, e);
116                 }
117                 return false;
118             case AUDIOCONTROL_FEATURE_AUDIO_MODULE_CALLBACK:
119                 try {
120                     return mAudioControl.getInterfaceVersion() > AIDL_AUDIO_CONTROL_VERSION_2;
121                 } catch (RemoteException e) {
122                     Slogf.w("supportsFeature Failed to get version for feature: " + feature, e);
123                 }
124                 return false;
125             case AUDIOCONTROL_FEATURE_AUDIO_CONFIGURATION:
126                 if (!Flags.audioControlHalConfiguration()) {
127                     Slogf.i(TAG, "supportsFeature AUDIOCONTROL_FEATURE_AUDIO_CONFIGURATION"
128                             + " not supported since audio control HAL config is disabled");
129                     return false;
130                 }
131                 try {
132                     return mAudioControl.getInterfaceVersion() > AIDL_AUDIO_CONTROL_VERSION_4;
133                 } catch (RemoteException e) {
134                     Slogf.w("supportsFeature Failed to get version for feature: " + feature, e);
135                 }
136                 Slogf.i(TAG, "supportsFeature requires audio control version "
137                         + AIDL_AUDIO_CONTROL_VERSION_5);
138                 return false;
139             default:
140                 return false;
141         }
142     }
143 
144     @Override
registerFocusListener(HalFocusListener focusListener)145     public void registerFocusListener(HalFocusListener focusListener) {
146         if (Slogf.isLoggable(TAG, Log.DEBUG)) {
147             Slogf.d(TAG, "Registering focus listener on AudioControl HAL");
148         }
149         IFocusListener listenerWrapper = new FocusListenerWrapper(focusListener);
150         try {
151             mAudioControl.registerFocusListener(listenerWrapper);
152         } catch (RemoteException e) {
153             Slogf.e(TAG, "Failed to register focus listener");
154             throw new IllegalStateException("IAudioControl#registerFocusListener failed", e);
155         }
156         mListenerRegistered = true;
157     }
158 
159     @Override
registerAudioGainCallback(HalAudioGainCallback gainCallback)160     public void registerAudioGainCallback(HalAudioGainCallback gainCallback) {
161         if (Log.isLoggable(TAG, Log.DEBUG)) {
162             Slogf.d(TAG, "Registering Audio Gain Callback on AudioControl HAL");
163         }
164         Objects.requireNonNull(gainCallback, "Audio Gain Callback can not be null");
165         IAudioGainCallback agc = new AudioGainCallbackWrapper(gainCallback);
166         try {
167             if (mAudioControl.getInterfaceVersion() < AIDL_AUDIO_CONTROL_VERSION_2) {
168                 Slogf.w(TAG, "Registering audio gain callback is not supported"
169                         + " for versions less than " + AIDL_AUDIO_CONTROL_VERSION_2);
170                 return;
171             }
172             mAudioControl.registerGainCallback(agc);
173         } catch (RemoteException e) {
174             Slogf.e(TAG, "Failed to register gain callback");
175             throw new IllegalStateException("IAudioControl#registerAudioGainCallback failed", e);
176         }
177         mGainCallbackRegistered = true;
178     }
179 
180     @Override
unregisterAudioGainCallback()181     public void unregisterAudioGainCallback() {
182         // Audio Gain Callback will be unregistered by HAL automatically
183     }
184 
185     @Override
onAudioFocusChange(PlaybackTrackMetadata metaData, int zoneId, int focusChange)186     public void onAudioFocusChange(PlaybackTrackMetadata metaData, int zoneId, int focusChange) {
187         if (Slogf.isLoggable(TAG, Log.DEBUG)) {
188             Slogf.d(TAG, "onAudioFocusChange: metadata %s, zoneId %d, focusChanged %d", metaData,
189                     zoneId, focusChange);
190         }
191         try {
192             mAudioControl.onAudioFocusChangeWithMetaData(metaData, zoneId, focusChange);
193         } catch (RemoteException e) {
194             Slogf.d(TAG, "onAudioFocusChange: failed with metadata, retry with usage.");
195             onAudioFocusChange(metaData.usage, zoneId, focusChange);
196         }
197     }
198 
onAudioFocusChange(@ttributeUsage int usage, int zoneId, int focusChange)199     private void onAudioFocusChange(@AttributeUsage int usage, int zoneId, int focusChange) {
200         if (Slogf.isLoggable(TAG, Log.DEBUG)) {
201             Slogf.d(TAG, "onAudioFocusChange: usage %s, zoneId %d, focusChanged %d",
202                     usageToString(usage), zoneId, focusChange);
203         }
204         try {
205             String usageName = usageToXsdString(usage);
206             mAudioControl.onAudioFocusChange(usageName, zoneId, focusChange);
207         } catch (RemoteException e) {
208             throw new IllegalStateException("Failed to query IAudioControl#onAudioFocusChange", e);
209         }
210     }
211 
212     @Override
213     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)214     public void dump(IndentingPrintWriter writer) {
215         writer.println("*AudioControlWrapperAidl*");
216         writer.increaseIndent();
217         try {
218             writer.printf("Aidl Version: %d\n", mAudioControl.getInterfaceVersion());
219         } catch (RemoteException e) {
220             Slogf.e(TAG, "dump getInterfaceVersion error", e);
221             writer.printf("Version: Could not be retrieved\n");
222         }
223         writer.printf("Focus listener registered on HAL? %b\n", mListenerRegistered);
224         writer.printf("Audio Gain Callback registered on HAL? %b\n", mGainCallbackRegistered);
225         writer.printf("Module change Callback set on HAL? %b\n", mModuleChangeCallbackRegistered);
226 
227         writer.println("Supported Features");
228         writer.increaseIndent();
229         writer.println("- AUDIOCONTROL_FEATURE_AUDIO_FOCUS");
230         writer.println("- AUDIOCONTROL_FEATURE_AUDIO_DUCKING");
231         if (supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_FOCUS_WITH_METADATA)) {
232             writer.println("- AUDIOCONTROL_FEATURE_AUDIO_FOCUS_WITH_METADATA");
233             writer.println("- AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK");
234         }
235         if (supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_MODULE_CALLBACK)) {
236             writer.println("- AUDIOCONTROL_FEATURE_AUDIO_MODULE_CALLBACK");
237         }
238         if (supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_CONFIGURATION)) {
239             writer.println("- AUDIOCONTROL_FEATURE_AUDIO_CONFIGURATION");
240         }
241         writer.decreaseIndent();
242 
243         writer.decreaseIndent();
244     }
245 
246     @Override
setFadeTowardFront(float value)247     public void setFadeTowardFront(float value) {
248         try {
249             mAudioControl.setFadeTowardFront(value);
250         } catch (RemoteException e) {
251             Slogf.e(TAG, "setFadeTowardFront with " + value + " failed", e);
252         }
253     }
254 
255     @Override
setBalanceTowardRight(float value)256     public void setBalanceTowardRight(float value) {
257         try {
258             mAudioControl.setBalanceTowardRight(value);
259         } catch (RemoteException e) {
260             Slogf.e(TAG, "setBalanceTowardRight with " + value + " failed", e);
261         }
262     }
263 
264     @Override
onDevicesToDuckChange(@onNull List<CarDuckingInfo> carDuckingInfos)265     public void onDevicesToDuckChange(@NonNull List<CarDuckingInfo> carDuckingInfos) {
266         Objects.requireNonNull(carDuckingInfos);
267         DuckingInfo[] duckingInfos = new DuckingInfo[carDuckingInfos.size()];
268         for (int i = 0; i < carDuckingInfos.size(); i++) {
269             CarDuckingInfo info = Objects.requireNonNull(carDuckingInfos.get(i));
270             duckingInfos[i] = CarHalAudioUtils.generateDuckingInfo(info);
271         }
272 
273         try {
274             mAudioControl.onDevicesToDuckChange(duckingInfos);
275         } catch (RemoteException e) {
276             Slogf.e(TAG, e, "onDevicesToDuckChange failed");
277         }
278     }
279 
280     @Override
onDevicesToMuteChange(@onNull List<MutingInfo> carZonesMutingInfo)281     public void onDevicesToMuteChange(@NonNull List<MutingInfo> carZonesMutingInfo) {
282         Objects.requireNonNull(carZonesMutingInfo, "Muting info can not be null");
283         Preconditions.checkArgument(!carZonesMutingInfo.isEmpty(), "Muting info can not be empty");
284         MutingInfo[] mutingInfoToHal = carZonesMutingInfo
285                 .toArray(new MutingInfo[carZonesMutingInfo.size()]);
286         try {
287             mAudioControl.onDevicesToMuteChange(mutingInfoToHal);
288         } catch (RemoteException e) {
289             Slogf.e(TAG, e, "onDevicesToMuteChange failed");
290         }
291     }
292 
293     @Override
setModuleChangeCallback(HalAudioModuleChangeCallback moduleChangeCallback)294     public void setModuleChangeCallback(HalAudioModuleChangeCallback moduleChangeCallback) {
295         Objects.requireNonNull(moduleChangeCallback, "Module change callback can not be null");
296 
297         IModuleChangeCallback callback = new ModuleChangeCallbackWrapper(moduleChangeCallback);
298         mExecutor.execute(new Runnable() {
299             @Override
300             public void run() {
301                 try {
302                     if (mAudioControl.getInterfaceVersion() < AIDL_AUDIO_CONTROL_VERSION_3) {
303                         Slogf.w(TAG, "Setting module change callback is not supported"
304                                 + " for versions less than " + AIDL_AUDIO_CONTROL_VERSION_3);
305                         return;
306                     }
307                     mAudioControl.setModuleChangeCallback(callback);
308                     mModuleChangeCallbackRegistered = true;
309                 } catch (RemoteException e) {
310                     throw new IllegalStateException(
311                             "IAudioControl#setModuleChangeCallback failed", e);
312                 } catch (UnsupportedOperationException e) {
313                     Slogf.w(TAG, "Failed to set module change callback, feature not supported");
314                 } catch (IllegalStateException e) {
315                     // we hit this if car service crashed and restarted. lets clear callbacks and
316                     // try again one more time.
317                     Slogf.w(TAG, "Module change callback already set, retry after clearing");
318                     try {
319                         mAudioControl.clearModuleChangeCallback();
320                         mAudioControl.setModuleChangeCallback(callback);
321                         mModuleChangeCallbackRegistered = true;
322                     } catch (RemoteException ex) {
323                         throw new IllegalStateException(
324                                 "IAudioControl#setModuleChangeCallback failed (after retry)", ex);
325                     } catch (IllegalStateException ex) {
326                         Slogf.e(TAG, ex, "Failed to set module change callback (after retry)");
327                         // lets  not throw any exception since it may lead to car service failure
328                     }
329                 }
330             }
331         });
332     }
333 
334     @Override
clearModuleChangeCallback()335     public void clearModuleChangeCallback() {
336         mExecutor.execute(new Runnable() {
337             @Override
338             public void run() {
339                 try {
340                     if (mAudioControl.getInterfaceVersion() < AIDL_AUDIO_CONTROL_VERSION_3) {
341                         Slogf.w(TAG, "Clearing module change callback is not supported"
342                                 + " for versions less than " + AIDL_AUDIO_CONTROL_VERSION_3);
343                         return;
344                     }
345                     mAudioControl.clearModuleChangeCallback();
346                     mModuleChangeCallbackRegistered = false;
347                 } catch (RemoteException e) {
348                     throw new IllegalStateException(
349                             "IAudioControl#clearModuleChangeCallback failed", e);
350                 } catch (UnsupportedOperationException e) {
351                     Slogf.w(TAG, "Failed to clear module change callback, feature not supported");
352                 }
353             }
354         });
355     }
356 
357     @Override
getAudioDeviceConfiguration()358     public AudioDeviceConfiguration getAudioDeviceConfiguration() {
359         if (!supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_CONFIGURATION)) {
360             return getDefaultAudioConfiguration();
361         }
362         try {
363             return mAudioControl.getAudioDeviceConfiguration();
364         } catch (RemoteException e) {
365             Slogf.w(TAG, "Failed to get audio device configuration", e);
366             return getDefaultAudioConfiguration();
367         } catch (UnsupportedOperationException e) {
368             Slogf.w(TAG, "Failed to get audio device configuration, feature not supported",
369                     e);
370             return getDefaultAudioConfiguration();
371         }
372     }
373 
374     @Override
getOutputMirroringDevices()375     public List<AudioPort> getOutputMirroringDevices() {
376         if (!supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_CONFIGURATION)) {
377             return EMPTY_LIST;
378         }
379         try {
380             return mAudioControl.getOutputMirroringDevices();
381         } catch (RemoteException e) {
382             Slogf.w(TAG, "Failed to get audio mirroring devices", e);
383             return EMPTY_LIST;
384         } catch (UnsupportedOperationException e) {
385             Slogf.w(TAG, "Failed to get audio mirroring devices, feature not supported",
386                     e);
387             return EMPTY_LIST;
388         }
389     }
390 
391     @Override
getCarAudioZones()392     public List<AudioZone> getCarAudioZones() {
393         if (!supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_CONFIGURATION)) {
394             return EMPTY_LIST;
395         }
396         try {
397             return mAudioControl.getCarAudioZones();
398         } catch (RemoteException e) {
399             Slogf.w(TAG, "Failed to get audio zones", e);
400             return EMPTY_LIST;
401         } catch (UnsupportedOperationException e) {
402             Slogf.w(TAG, "Failed to get audio zones, feature not supported", e);
403             return EMPTY_LIST;
404         }
405     }
406 
407     @Override
linkToDeath(@ullable AudioControlDeathRecipient deathRecipient)408     public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
409         try {
410             mBinder.linkToDeath(this, 0);
411             mDeathRecipient = deathRecipient;
412         } catch (RemoteException e) {
413             throw new IllegalStateException("Call to IAudioControl#linkToDeath failed", e);
414         }
415     }
416 
417     @Override
unlinkToDeath()418     public void unlinkToDeath() {
419         mBinder.unlinkToDeath(this, 0);
420         mDeathRecipient = null;
421     }
422 
423     @Override
binderDied()424     public void binderDied() {
425         Slogf.w(TAG, "AudioControl HAL died. Fetching new handle");
426         mBinder.unlinkToDeath(this, 0);
427         mListenerRegistered = false;
428         mGainCallbackRegistered = false;
429         mModuleChangeCallbackRegistered = false;
430         mBinder = AudioControlWrapperAidl.getService();
431         mAudioControl = IAudioControl.Stub.asInterface(mBinder);
432         // TODO(b/284043199): Refactor the retry logic out and add delay between retry.
433         try {
434             mBinder.linkToDeath(this, 0);
435         } catch (RemoteException e) {
436             // Avoid crashing the binder thread.
437             Slogf.e(TAG, "Call to IAudioControl#linkToDeath failed", e);
438         }
439         if (mDeathRecipient != null) {
440             mDeathRecipient.serviceDied();
441         }
442     }
443 
getDefaultAudioConfiguration()444     private AudioDeviceConfiguration getDefaultAudioConfiguration() {
445         AudioDeviceConfiguration configuration = new AudioDeviceConfiguration();
446         configuration.routingConfig = RoutingDeviceConfiguration.DEFAULT_AUDIO_ROUTING;
447         return configuration;
448     }
449 
450     private static final class FocusListenerWrapper extends IFocusListener.Stub {
451         private final HalFocusListener mListener;
452 
FocusListenerWrapper(HalFocusListener halFocusListener)453         FocusListenerWrapper(HalFocusListener halFocusListener) {
454             mListener = halFocusListener;
455         }
456 
457         @Override
458         @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
getInterfaceVersion()459         public int getInterfaceVersion() {
460             return this.VERSION;
461         }
462 
463         @Override
464         @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
getInterfaceHash()465         public String getInterfaceHash() {
466             return this.HASH;
467         }
468 
469         @Override
requestAudioFocus(String usage, int zoneId, int focusGain)470         public void requestAudioFocus(String usage, int zoneId, int focusGain) {
471             @AttributeUsage int usageValue = xsdStringToUsage(usage);
472             requestAudioFocus(usageValue, zoneId, focusGain);
473         }
474 
475         @Override
abandonAudioFocus(String usage, int zoneId)476         public void abandonAudioFocus(String usage, int zoneId) {
477             @AttributeUsage int usageValue = xsdStringToUsage(usage);
478             abandonAudioFocus(usageValue, zoneId);
479         }
480 
481         @Override
requestAudioFocusWithMetaData( PlaybackTrackMetadata playbackMetaData, int zoneId, int focusGain)482         public void requestAudioFocusWithMetaData(
483                 PlaybackTrackMetadata playbackMetaData, int zoneId, int focusGain) {
484             if (Log.isLoggable(TAG, Log.DEBUG)) {
485                 Slogf.d(TAG, "requestAudioFocusWithMetaData metadata=%s, zoneId=%d, focusGain=%d",
486                         playbackMetaData, zoneId, focusGain);
487             }
488             mListener.requestAudioFocus(playbackMetaData, zoneId, focusGain);
489         }
490 
491         @Override
abandonAudioFocusWithMetaData( PlaybackTrackMetadata playbackMetaData, int zoneId)492         public void abandonAudioFocusWithMetaData(
493                 PlaybackTrackMetadata playbackMetaData, int zoneId) {
494             if (Log.isLoggable(TAG, Log.DEBUG)) {
495                 Slogf.d(TAG, "abandonAudioFocusWithMetaData metadata=%s, zoneId=%d",
496                         playbackMetaData, zoneId);
497             }
498             mListener.abandonAudioFocus(playbackMetaData, zoneId);
499         }
500 
abandonAudioFocus(int usage, int zoneId)501         private void abandonAudioFocus(int usage, int zoneId) {
502             abandonAudioFocusWithMetaData(usageToMetadata(usage), zoneId);
503         }
504 
requestAudioFocus(int usage, int zoneId, int focusGain)505         private void requestAudioFocus(int usage, int zoneId, int focusGain) {
506             requestAudioFocusWithMetaData(usageToMetadata(usage), zoneId, focusGain);
507         }
508     }
509 
510     private static final class AudioGainCallbackWrapper extends IAudioGainCallback.Stub {
511         private @NonNull final HalAudioGainCallback mCallback;
512 
AudioGainCallbackWrapper(@onNull HalAudioGainCallback gainCallback)513         AudioGainCallbackWrapper(@NonNull HalAudioGainCallback gainCallback) {
514             mCallback = gainCallback;
515         }
516 
517         @Override
518         @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
getInterfaceVersion()519         public int getInterfaceVersion() {
520             return VERSION;
521         }
522 
523         @Override
524         @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
getInterfaceHash()525         public String getInterfaceHash() {
526             return HASH;
527         }
528 
529         @Override
onAudioDeviceGainsChanged(int[] halReasons, AudioGainConfigInfo[] gains)530         public void onAudioDeviceGainsChanged(int[] halReasons, AudioGainConfigInfo[] gains) {
531             List<CarAudioGainConfigInfo> carAudioGainConfigs = new ArrayList<>();
532             for (int index = 0; index < gains.length; index++) {
533                 AudioGainConfigInfo gain = gains[index];
534                 carAudioGainConfigs.add(new CarAudioGainConfigInfo(gain));
535             }
536             List<Integer> reasonsList = new ArrayList<>();
537             for (int index = 0; index < halReasons.length; index++) {
538                 int halReason = halReasons[index];
539                 if (!HalAudioGainCallback.isReasonValid(halReason)) {
540                     Slogf.e(
541                             TAG,
542                             "onAudioDeviceGainsChanged invalid reasons %d reported, skipped",
543                             halReason);
544                     continue;
545                 }
546                 reasonsList.add(halReason);
547             }
548             if (Log.isLoggable(TAG, Log.DEBUG)) {
549                 List<String> gainsString = new ArrayList<>();
550                 for (int i = 0; i < carAudioGainConfigs.size(); i++) {
551                     gainsString.add(carAudioGainConfigs.get(i).toString());
552                 }
553                 String gainsLiteral = String.join(",", gainsString);
554 
555                 List<String> reasonsString = new ArrayList<>();
556                 for (int i = 0; i < reasonsString.size(); i++) {
557                     reasonsString.add(HalAudioGainCallback.reasonToString(reasonsList.get(i)));
558                 }
559                 String reasonsLiteral = String.join(",", reasonsString);
560                 Slogf.d(
561                         TAG,
562                         "onAudioDeviceGainsChanged for reasons=[%s], gains=[%s]",
563                         reasonsLiteral,
564                         gainsLiteral);
565             }
566             mCallback.onAudioDeviceGainsChanged(reasonsList, carAudioGainConfigs);
567         }
568     }
569 
570     private static final class ModuleChangeCallbackWrapper extends IModuleChangeCallback.Stub {
571         private final HalAudioModuleChangeCallback mCallback;
572 
ModuleChangeCallbackWrapper(HalAudioModuleChangeCallback callback)573         ModuleChangeCallbackWrapper(HalAudioModuleChangeCallback callback) {
574             mCallback = callback;
575         }
576 
577         @Override
578         @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
getInterfaceVersion()579         public int getInterfaceVersion() {
580             return this.VERSION;
581         }
582 
583         @Override
584         @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
getInterfaceHash()585         public String getInterfaceHash() {
586             return this.HASH;
587         }
588 
589         @Override
onAudioPortsChanged(AudioPort[] audioPorts)590         public void onAudioPortsChanged(AudioPort[] audioPorts) {
591             mCallback.onAudioPortsChanged(convertAudioPortToHalAudioDevice(audioPorts));
592         }
593     }
594 
convertAudioPortToHalAudioDevice(AudioPort[] ports)595     private static List<HalAudioDeviceInfo> convertAudioPortToHalAudioDevice(AudioPort[] ports) {
596         List<HalAudioDeviceInfo> halAudioDeviceInfos = new ArrayList<>();
597         for (AudioPort port : ports) {
598             halAudioDeviceInfos.add(new HalAudioDeviceInfo(port));
599         }
600         return halAudioDeviceInfos;
601     }
602 }
603