• 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 com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.hardware.automotive.audiocontrol.DuckingInfo;
24 import android.hardware.automotive.audiocontrol.IAudioControl;
25 import android.hardware.automotive.audiocontrol.IFocusListener;
26 import android.hardware.automotive.audiocontrol.MutingInfo;
27 import android.media.AudioAttributes;
28 import android.media.AudioAttributes.AttributeUsage;
29 import android.os.Binder;
30 import android.os.IBinder;
31 import android.os.RemoteException;
32 import android.os.ServiceManager;
33 import android.util.IndentingPrintWriter;
34 import android.util.Log;
35 import android.util.Slog;
36 
37 import com.android.car.CarLog;
38 import com.android.car.audio.CarDuckingInfo;
39 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
40 import com.android.internal.util.Preconditions;
41 
42 import java.util.List;
43 import java.util.Objects;
44 
45 /**
46  * Wrapper for AIDL interface for AudioControl HAL
47  */
48 public final class AudioControlWrapperAidl implements AudioControlWrapper {
49     private static final String TAG = CarLog.tagFor(AudioControlWrapperAidl.class);
50     private static final String AUDIO_CONTROL_SERVICE =
51             "android.hardware.automotive.audiocontrol.IAudioControl/default";
52     private IBinder mBinder;
53     private IAudioControl mAudioControl;
54     private boolean mListenerRegistered = false;
55 
56     private AudioControlDeathRecipient mDeathRecipient;
57 
getService()58     static @Nullable IBinder getService() {
59         return Binder.allowBlocking(ServiceManager.waitForDeclaredService(
60                 AUDIO_CONTROL_SERVICE));
61     }
62 
AudioControlWrapperAidl(IBinder binder)63     AudioControlWrapperAidl(IBinder binder) {
64         mBinder = Objects.requireNonNull(binder);
65         mAudioControl = IAudioControl.Stub.asInterface(binder);
66     }
67 
68     @Override
unregisterFocusListener()69     public void unregisterFocusListener() {
70         // Focus listener will be unregistered by HAL automatically
71     }
72 
73     @Override
supportsFeature(int feature)74     public boolean supportsFeature(int feature) {
75         switch (feature) {
76             case AUDIOCONTROL_FEATURE_AUDIO_FOCUS:
77             case AUDIOCONTROL_FEATURE_AUDIO_DUCKING:
78             case AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING:
79                 return true;
80             default:
81                 return false;
82         }
83     }
84 
85     @Override
registerFocusListener(HalFocusListener focusListener)86     public void registerFocusListener(HalFocusListener focusListener) {
87         if (Log.isLoggable(TAG, Log.DEBUG)) {
88             Slog.d(TAG, "Registering focus listener on AudioControl HAL");
89         }
90         IFocusListener listenerWrapper = new FocusListenerWrapper(focusListener);
91         try {
92             mAudioControl.registerFocusListener(listenerWrapper);
93         } catch (RemoteException e) {
94             Slog.e(TAG, "Failed to register focus listener");
95             throw new IllegalStateException("IAudioControl#registerFocusListener failed", e);
96         }
97         mListenerRegistered = true;
98     }
99 
100     @Override
onAudioFocusChange(@ttributeUsage int usage, int zoneId, int focusChange)101     public void onAudioFocusChange(@AttributeUsage int usage, int zoneId, int focusChange) {
102         if (Log.isLoggable(TAG, Log.DEBUG)) {
103             Slog.d(TAG, "onAudioFocusChange: usage " + AudioAttributes.usageToString(usage)
104                     + ", zoneId " + zoneId + ", focusChange " + focusChange);
105         }
106         try {
107             String usageName = AudioAttributes.usageToXsdString(usage);
108             mAudioControl.onAudioFocusChange(usageName, zoneId, focusChange);
109         } catch (RemoteException e) {
110             throw new IllegalStateException("Failed to query IAudioControl#onAudioFocusChange", e);
111         }
112     }
113 
114     @Override
115     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)116     public void dump(IndentingPrintWriter writer) {
117         writer.println("*AudioControlWrapperAidl*");
118         writer.increaseIndent();
119         writer.printf("Focus listener registered on HAL? %b\n", mListenerRegistered);
120 
121         writer.println("Supported Features");
122         writer.increaseIndent();
123         writer.println("- AUDIOCONTROL_FEATURE_AUDIO_FOCUS");
124         writer.println("- AUDIOCONTROL_FEATURE_AUDIO_DUCKING");
125         writer.decreaseIndent();
126 
127         writer.decreaseIndent();
128     }
129 
130     @Override
setFadeTowardFront(float value)131     public void setFadeTowardFront(float value) {
132         try {
133             mAudioControl.setFadeTowardFront(value);
134         } catch (RemoteException e) {
135             Slog.e(TAG, "setFadeTowardFront with " + value + " failed", e);
136         }
137     }
138 
139     @Override
setBalanceTowardRight(float value)140     public void setBalanceTowardRight(float value) {
141         try {
142             mAudioControl.setBalanceTowardRight(value);
143         } catch (RemoteException e) {
144             Slog.e(TAG, "setBalanceTowardRight with " + value + " failed", e);
145         }
146     }
147 
148     @Override
onDevicesToDuckChange(@onNull List<CarDuckingInfo> carDuckingInfos)149     public void onDevicesToDuckChange(@NonNull List<CarDuckingInfo> carDuckingInfos) {
150         Objects.requireNonNull(carDuckingInfos);
151         DuckingInfo[] duckingInfos = new DuckingInfo[carDuckingInfos.size()];
152         for (int i = 0; i < carDuckingInfos.size(); i++) {
153             CarDuckingInfo info = Objects.requireNonNull(carDuckingInfos.get(i));
154             duckingInfos[i] = info.generateDuckingInfo();
155         }
156 
157         try {
158             mAudioControl.onDevicesToDuckChange(duckingInfos);
159         } catch (RemoteException e) {
160             Slog.e(TAG, "onDevicesToDuckChange failed", e);
161         }
162     }
163 
164     @Override
onDevicesToMuteChange(@onNull List<MutingInfo> carZonesMutingInfo)165     public void onDevicesToMuteChange(@NonNull List<MutingInfo> carZonesMutingInfo) {
166         Objects.requireNonNull(carZonesMutingInfo, "Muting info can not be null");
167         Preconditions.checkArgument(!carZonesMutingInfo.isEmpty(), "Muting info can not be empty");
168         MutingInfo[] mutingInfoToHal = carZonesMutingInfo
169                 .toArray(new MutingInfo[carZonesMutingInfo.size()]);
170         try {
171             mAudioControl.onDevicesToMuteChange(mutingInfoToHal);
172         } catch (RemoteException e) {
173             Slog.e(TAG, "onDevicesToMuteChange failed", e);
174         }
175     }
176 
177     @Override
linkToDeath(@ullable AudioControlDeathRecipient deathRecipient)178     public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
179         try {
180             mBinder.linkToDeath(this::binderDied, 0);
181             mDeathRecipient = deathRecipient;
182         } catch (RemoteException e) {
183             throw new IllegalStateException("Call to IAudioControl#linkToDeath failed", e);
184         }
185     }
186 
187     @Override
unlinkToDeath()188     public void unlinkToDeath() {
189         mBinder.unlinkToDeath(this::binderDied, 0);
190         mDeathRecipient = null;
191     }
192 
binderDied()193     private void binderDied() {
194         Slog.w(TAG, "AudioControl HAL died. Fetching new handle");
195         mListenerRegistered = false;
196         mBinder = AudioControlWrapperAidl.getService();
197         mAudioControl = IAudioControl.Stub.asInterface(mBinder);
198         linkToDeath(mDeathRecipient);
199         if (mDeathRecipient != null) {
200             mDeathRecipient.serviceDied();
201         }
202     }
203 
204     private static final class FocusListenerWrapper extends IFocusListener.Stub {
205         private final HalFocusListener mListener;
206 
FocusListenerWrapper(HalFocusListener halFocusListener)207         FocusListenerWrapper(HalFocusListener halFocusListener) {
208             mListener = halFocusListener;
209         }
210 
211         @Override
getInterfaceVersion()212         public int getInterfaceVersion() {
213             return this.VERSION;
214         }
215 
216         @Override
getInterfaceHash()217         public String getInterfaceHash() {
218             return this.HASH;
219         }
220 
221         @Override
requestAudioFocus(String usage, int zoneId, int focusGain)222         public void requestAudioFocus(String usage, int zoneId, int focusGain) {
223             @AttributeUsage int usageValue = AudioAttributes.xsdStringToUsage(usage);
224             mListener.requestAudioFocus(usageValue, zoneId, focusGain);
225         }
226 
227         @Override
abandonAudioFocus(String usage, int zoneId)228         public void abandonAudioFocus(String usage, int zoneId) {
229             @AttributeUsage int usageValue = AudioAttributes.xsdStringToUsage(usage);
230             mListener.abandonAudioFocus(usageValue, zoneId);
231         }
232     }
233 }
234