• 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.MutingInfo;
24 import android.hardware.automotive.audiocontrol.V2_0.IAudioControl;
25 import android.hardware.automotive.audiocontrol.V2_0.ICloseHandle;
26 import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
27 import android.media.AudioAttributes;
28 import android.media.AudioAttributes.AttributeUsage;
29 import android.os.RemoteException;
30 import android.util.IndentingPrintWriter;
31 import android.util.Log;
32 import android.util.Slog;
33 
34 import com.android.car.CarLog;
35 import com.android.car.audio.CarDuckingInfo;
36 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
37 
38 import java.util.List;
39 import java.util.NoSuchElementException;
40 import java.util.Objects;
41 
42 /**
43  * Wrapper for IAudioControl@2.0.
44  */
45 public final class AudioControlWrapperV2 implements AudioControlWrapper {
46     private static final String TAG = CarLog.tagFor(AudioControlWrapperV2.class);
47 
48     private IAudioControl mAudioControlV2;
49 
50     private AudioControlDeathRecipient mDeathRecipient;
51     private ICloseHandle mCloseHandle;
52 
getService()53     static @Nullable IAudioControl getService() {
54         try {
55             return IAudioControl.getService(true);
56         } catch (RemoteException e) {
57             throw new IllegalStateException("Failed to get IAudioControl@2.0 service", e);
58         } catch (NoSuchElementException e) {
59             return null;
60         }
61     }
62 
AudioControlWrapperV2(IAudioControl audioControlV2)63     AudioControlWrapperV2(IAudioControl audioControlV2) {
64         mAudioControlV2 = Objects.requireNonNull(audioControlV2);
65     }
66 
67     @Override
unregisterFocusListener()68     public void unregisterFocusListener() {
69         if (mCloseHandle != null) {
70             try {
71                 mCloseHandle.close();
72             } catch (RemoteException e) {
73                 Slog.e(TAG, "Failed to close focus listener", e);
74             } finally {
75                 mCloseHandle = null;
76             }
77         }
78     }
79 
80     @Override
supportsFeature(int feature)81     public boolean supportsFeature(int feature) {
82         if (feature == AUDIOCONTROL_FEATURE_AUDIO_FOCUS) {
83             return true;
84         }
85         return false;
86     }
87 
88     @Override
registerFocusListener(HalFocusListener focusListener)89     public void registerFocusListener(HalFocusListener focusListener) {
90         Slog.d(TAG, "Registering focus listener on AudioControl HAL");
91         IFocusListener listenerWrapper = new FocusListenerWrapper(focusListener);
92         try {
93             mCloseHandle = mAudioControlV2.registerFocusListener(listenerWrapper);
94         } catch (RemoteException e) {
95             Slog.e(TAG, "Failed to register focus listener");
96             throw new IllegalStateException("IAudioControl#registerFocusListener failed", e);
97         }
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             mAudioControlV2.onAudioFocusChange(usage, zoneId, focusChange);
108         } catch (RemoteException e) {
109             throw new IllegalStateException("Failed to query IAudioControl#onAudioFocusChange", e);
110         }
111     }
112 
113     @Override
114     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)115     public void dump(IndentingPrintWriter writer) {
116         writer.println("*AudioControlWrapperV2*");
117         writer.increaseIndent();
118         writer.printf("Focus listener registered on HAL? %b\n", (mCloseHandle != null));
119 
120         writer.println("Supported Features");
121         writer.increaseIndent();
122         writer.println("- AUDIOCONTROL_FEATURE_AUDIO_FOCUS");
123         writer.decreaseIndent();
124 
125         writer.decreaseIndent();
126     }
127 
128     @Override
setFadeTowardFront(float value)129     public void setFadeTowardFront(float value) {
130         try {
131             mAudioControlV2.setFadeTowardFront(value);
132         } catch (RemoteException e) {
133             Slog.e(TAG, "setFadeTowardFront failed", e);
134         }
135     }
136 
137     @Override
setBalanceTowardRight(float value)138     public void setBalanceTowardRight(float value) {
139         try {
140             mAudioControlV2.setBalanceTowardRight(value);
141         } catch (RemoteException e) {
142             Slog.e(TAG, "setBalanceTowardRight failed", e);
143         }
144     }
145 
146     @Override
onDevicesToDuckChange(List<CarDuckingInfo> carDuckingInfos)147     public void onDevicesToDuckChange(List<CarDuckingInfo> carDuckingInfos) {
148         throw new UnsupportedOperationException("HAL ducking is unsupported for IAudioControl@2.0");
149     }
150 
151     @Override
onDevicesToMuteChange(@onNull List<MutingInfo> carZonesMutingInfo)152     public void onDevicesToMuteChange(@NonNull List<MutingInfo> carZonesMutingInfo) {
153         throw new UnsupportedOperationException("HAL muting is unsupported for IAudioControl@2.0");
154     }
155 
156     @Override
linkToDeath(@ullable AudioControlDeathRecipient deathRecipient)157     public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
158         try {
159             mAudioControlV2.linkToDeath(this::serviceDied, 0);
160             mDeathRecipient = deathRecipient;
161         } catch (RemoteException e) {
162             throw new IllegalStateException("Call to IAudioControl@2.0#linkToDeath failed", e);
163         }
164     }
165 
166     @Override
unlinkToDeath()167     public void unlinkToDeath() {
168         try {
169             mAudioControlV2.unlinkToDeath(this::serviceDied);
170             mDeathRecipient = null;
171         } catch (RemoteException e) {
172             throw new IllegalStateException("Call to IAudioControl@2.0#unlinkToDeath failed", e);
173         }
174     }
175 
serviceDied(long cookie)176     private void serviceDied(long cookie) {
177         Slog.w(TAG, "IAudioControl@2.0 died. Fetching new handle");
178         mAudioControlV2 = AudioControlWrapperV2.getService();
179         linkToDeath(mDeathRecipient);
180         if (mDeathRecipient != null) {
181             mDeathRecipient.serviceDied();
182         }
183     }
184 
185     private final class FocusListenerWrapper extends IFocusListener.Stub {
186         private final HalFocusListener mListener;
187 
FocusListenerWrapper(HalFocusListener halFocusListener)188         FocusListenerWrapper(HalFocusListener halFocusListener) {
189             mListener = halFocusListener;
190         }
191 
192         @Override
requestAudioFocus(int usage, int zoneId, int focusGain)193         public void requestAudioFocus(int usage, int zoneId, int focusGain) throws RemoteException {
194             mListener.requestAudioFocus(usage, zoneId, focusGain);
195         }
196 
197         @Override
abandonAudioFocus(int usage, int zoneId)198         public void abandonAudioFocus(int usage, int zoneId) throws RemoteException {
199             mListener.abandonAudioFocus(usage, zoneId);
200         }
201     }
202 }
203