• 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 
21 import static com.android.car.audio.CarHalAudioUtils.usageToMetadata;
22 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.car.builtin.util.Slogf;
27 import android.hardware.audio.common.PlaybackTrackMetadata;
28 import android.hardware.automotive.audiocontrol.AudioDeviceConfiguration;
29 import android.hardware.automotive.audiocontrol.AudioZone;
30 import android.hardware.automotive.audiocontrol.MutingInfo;
31 import android.hardware.automotive.audiocontrol.V2_0.IAudioControl;
32 import android.hardware.automotive.audiocontrol.V2_0.ICloseHandle;
33 import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
34 import android.media.audio.common.AudioPort;
35 import android.os.RemoteException;
36 import android.util.Log;
37 
38 import com.android.car.CarLog;
39 import com.android.car.audio.CarDuckingInfo;
40 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
41 import com.android.car.internal.util.IndentingPrintWriter;
42 
43 import java.util.List;
44 import java.util.NoSuchElementException;
45 import java.util.Objects;
46 
47 /**
48  * Wrapper for IAudioControl@2.0.
49  */
50 public final class AudioControlWrapperV2 implements AudioControlWrapper {
51     private static final String TAG = CarLog.tagFor(AudioControlWrapperV2.class);
52 
53     private IAudioControl mAudioControlV2;
54 
55     private AudioControlDeathRecipient mDeathRecipient;
56     private ICloseHandle mCloseHandle;
57 
getService()58     static @Nullable IAudioControl getService() {
59         try {
60             return IAudioControl.getService(true);
61         } catch (RemoteException e) {
62             throw new IllegalStateException("Failed to get IAudioControl@2.0 service", e);
63         } catch (NoSuchElementException e) {
64             return null;
65         }
66     }
67 
AudioControlWrapperV2(IAudioControl audioControlV2)68     AudioControlWrapperV2(IAudioControl audioControlV2) {
69         mAudioControlV2 = Objects.requireNonNull(audioControlV2);
70     }
71 
72     @Override
unregisterFocusListener()73     public void unregisterFocusListener() {
74         if (mCloseHandle != null) {
75             try {
76                 mCloseHandle.close();
77             } catch (RemoteException e) {
78                 Slogf.e(TAG, "Failed to close focus listener", e);
79             } finally {
80                 mCloseHandle = null;
81             }
82         }
83     }
84 
85     @Override
supportsFeature(int feature)86     public boolean supportsFeature(int feature) {
87         return feature == AUDIOCONTROL_FEATURE_AUDIO_FOCUS;
88     }
89 
90     @Override
registerFocusListener(HalFocusListener focusListener)91     public void registerFocusListener(HalFocusListener focusListener) {
92         Slogf.d(TAG, "Registering focus listener on AudioControl HAL");
93         IFocusListener listenerWrapper = new FocusListenerWrapper(focusListener);
94         try {
95             mCloseHandle = mAudioControlV2.registerFocusListener(listenerWrapper);
96         } catch (RemoteException e) {
97             Slogf.e(TAG, "Failed to register focus listener");
98             throw new IllegalStateException("IAudioControl#registerFocusListener failed", e);
99         }
100     }
101 
102     @Override
registerAudioGainCallback(HalAudioGainCallback gainCallback)103     public void registerAudioGainCallback(HalAudioGainCallback gainCallback) {
104         throw new UnsupportedOperationException(getUnsupportedMessage("Audio Gain Callback"));
105     }
106 
107     @Override
unregisterAudioGainCallback()108     public void unregisterAudioGainCallback() {
109         throw new UnsupportedOperationException(getUnsupportedMessage("Audio Gain Callback"));
110     }
111 
112     @Override
onAudioFocusChange(PlaybackTrackMetadata metaData, int zoneId, int focusChange)113     public void onAudioFocusChange(PlaybackTrackMetadata metaData, int zoneId, int focusChange) {
114         int usage = metaData.usage;
115         if (Slogf.isLoggable(TAG, Log.DEBUG)) {
116             Slogf.d(TAG, "onAudioFocusChange: usage " + usageToString(usage)
117                     + ", zoneId " + zoneId + ", focusChange " + focusChange);
118         }
119         try {
120             mAudioControlV2.onAudioFocusChange(usage, zoneId, focusChange);
121         } catch (RemoteException e) {
122             throw new IllegalStateException("Failed to query IAudioControl#onAudioFocusChange", e);
123         }
124     }
125 
126     @Override
127     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)128     public void dump(IndentingPrintWriter writer) {
129         writer.println("*AudioControlWrapperV2*");
130         writer.increaseIndent();
131         writer.printf("Focus listener registered on HAL? %b\n", (mCloseHandle != null));
132 
133         writer.println("Supported Features");
134         writer.increaseIndent();
135         writer.println("- AUDIOCONTROL_FEATURE_AUDIO_FOCUS");
136         writer.decreaseIndent();
137 
138         writer.decreaseIndent();
139     }
140 
141     @Override
setFadeTowardFront(float value)142     public void setFadeTowardFront(float value) {
143         try {
144             mAudioControlV2.setFadeTowardFront(value);
145         } catch (RemoteException e) {
146             Slogf.e(TAG, "setFadeTowardFront failed", e);
147         }
148     }
149 
150     @Override
setBalanceTowardRight(float value)151     public void setBalanceTowardRight(float value) {
152         try {
153             mAudioControlV2.setBalanceTowardRight(value);
154         } catch (RemoteException e) {
155             Slogf.e(TAG, "setBalanceTowardRight failed", e);
156         }
157     }
158 
159     @Override
onDevicesToDuckChange(List<CarDuckingInfo> carDuckingInfos)160     public void onDevicesToDuckChange(List<CarDuckingInfo> carDuckingInfos) {
161         throw new UnsupportedOperationException(getUnsupportedMessage("HAL ducking"));
162     }
163 
164     @Override
onDevicesToMuteChange(@onNull List<MutingInfo> carZonesMutingInfo)165     public void onDevicesToMuteChange(@NonNull List<MutingInfo> carZonesMutingInfo) {
166         throw new UnsupportedOperationException(getUnsupportedMessage("HAL muting"));
167     }
168 
169     @Override
setModuleChangeCallback(HalAudioModuleChangeCallback moduleChangeCallback)170     public void setModuleChangeCallback(HalAudioModuleChangeCallback moduleChangeCallback) {
171         throw new UnsupportedOperationException(getUnsupportedMessage("Module change callback"));
172     }
173 
174     @Override
clearModuleChangeCallback()175     public void clearModuleChangeCallback() {
176         throw new UnsupportedOperationException(getUnsupportedMessage("Module change callback"));
177     }
178 
179     @Override
getAudioDeviceConfiguration()180     public AudioDeviceConfiguration getAudioDeviceConfiguration() {
181         throw new UnsupportedOperationException(getUnsupportedMessage("Audio device configs"));
182     }
183 
184     @Override
getOutputMirroringDevices()185     public List<AudioPort> getOutputMirroringDevices() {
186         throw new UnsupportedOperationException(getUnsupportedMessage("Output mirror devices"));
187     }
188 
189     @Override
getCarAudioZones()190     public List<AudioZone> getCarAudioZones() {
191         throw new UnsupportedOperationException(getUnsupportedMessage("Audio zones"));
192     }
193 
getUnsupportedMessage(String operation)194     private static String getUnsupportedMessage(String operation) {
195         return operation + " is unsupported for IAudioControl@2.0";
196     }
197 
198     @Override
linkToDeath(@ullable AudioControlDeathRecipient deathRecipient)199     public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
200         try {
201             mAudioControlV2.linkToDeath(this::serviceDied, 0);
202             mDeathRecipient = deathRecipient;
203         } catch (RemoteException e) {
204             throw new IllegalStateException("Call to IAudioControl@2.0#linkToDeath failed", e);
205         }
206     }
207 
208     @Override
unlinkToDeath()209     public void unlinkToDeath() {
210         try {
211             mAudioControlV2.unlinkToDeath(this::serviceDied);
212             mDeathRecipient = null;
213         } catch (RemoteException e) {
214             throw new IllegalStateException("Call to IAudioControl@2.0#unlinkToDeath failed", e);
215         }
216     }
217 
serviceDied(long cookie)218     private void serviceDied(long cookie) {
219         Slogf.w(TAG, "IAudioControl@2.0 died. Fetching new handle");
220         mAudioControlV2 = AudioControlWrapperV2.getService();
221         linkToDeath(mDeathRecipient);
222         if (mDeathRecipient != null) {
223             mDeathRecipient.serviceDied();
224         }
225     }
226 
227     private static final class FocusListenerWrapper extends IFocusListener.Stub {
228         private final HalFocusListener mListener;
229 
FocusListenerWrapper(HalFocusListener halFocusListener)230         FocusListenerWrapper(HalFocusListener halFocusListener) {
231             mListener = halFocusListener;
232         }
233 
234         @Override
requestAudioFocus(int usage, int zoneId, int focusGain)235         public void requestAudioFocus(int usage, int zoneId, int focusGain) throws RemoteException {
236             mListener.requestAudioFocus(usageToMetadata(usage), zoneId, focusGain);
237         }
238 
239         @Override
abandonAudioFocus(int usage, int zoneId)240         public void abandonAudioFocus(int usage, int zoneId) throws RemoteException {
241             mListener.abandonAudioFocus(usageToMetadata(usage), zoneId);
242         }
243     }
244 }
245