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.car.builtin.util.Slogf;
24 import android.hardware.audio.common.PlaybackTrackMetadata;
25 import android.hardware.automotive.audiocontrol.MutingInfo;
26 import android.hardware.automotive.audiocontrol.V1_0.IAudioControl;
27 import android.os.RemoteException;
28 
29 import com.android.car.CarLog;
30 import com.android.car.audio.CarAudioContext;
31 import com.android.car.audio.CarDuckingInfo;
32 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
33 import com.android.car.internal.util.IndentingPrintWriter;
34 import com.android.internal.annotations.VisibleForTesting;
35 
36 import java.util.List;
37 import java.util.NoSuchElementException;
38 import java.util.Objects;
39 
40 /**
41  * Wrapper for IAudioControl@1.0.
42  */
43 public final class AudioControlWrapperV1 implements AudioControlWrapper {
44     private static final String TAG = CarLog.tagFor(AudioControlWrapperV1.class);
45 
46     private IAudioControl mAudioControlV1;
47     private AudioControlDeathRecipient mDeathRecipient;
48 
49     /**
50      * Gets IAudioControl@1.0 service if registered.
51      */
getService()52     static @Nullable IAudioControl getService() {
53         try {
54             return IAudioControl.getService(true);
55         } catch (RemoteException e) {
56             throw new IllegalStateException("Failed to get IAudioControl@1.0 service", e);
57         } catch (NoSuchElementException e) {
58             return null;
59         }
60     }
61 
62     @VisibleForTesting
AudioControlWrapperV1(IAudioControl audioControlV1)63     AudioControlWrapperV1(IAudioControl audioControlV1) {
64         mAudioControlV1 = Objects.requireNonNull(audioControlV1);
65     }
66 
67     @Override
registerFocusListener(HalFocusListener focusListener)68     public void registerFocusListener(HalFocusListener focusListener) {
69         throw new UnsupportedOperationException(
70                 "Focus listener is unsupported for IAudioControl@1.0");
71     }
72 
73     @Override
unregisterFocusListener()74     public void unregisterFocusListener() {
75         throw new UnsupportedOperationException(
76                 "Focus listener is unsupported for IAudioControl@1.0");
77     }
78 
79     @Override
registerAudioGainCallback(HalAudioGainCallback gainCallback)80     public void registerAudioGainCallback(HalAudioGainCallback gainCallback) {
81         throw new UnsupportedOperationException(
82                 "Audio Gain Callback is unsupported for IAudioControl@1.0");
83     }
84 
85     @Override
unregisterAudioGainCallback()86     public void unregisterAudioGainCallback() {
87         throw new UnsupportedOperationException(
88                 "Audio Gain Callback is unsupported for IAudioControl@1.0");
89     }
90 
91     @Override
supportsFeature(int feature)92     public boolean supportsFeature(int feature) {
93         return false;
94     }
95 
96     @Override
onAudioFocusChange(PlaybackTrackMetadata metaData, int zoneId, int focusChange)97     public void onAudioFocusChange(PlaybackTrackMetadata metaData, int zoneId, int focusChange) {
98         throw new UnsupportedOperationException(
99                 "Focus listener is unsupported for IAudioControl@1.0");
100     }
101 
102     @Override
103     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)104     public void dump(IndentingPrintWriter writer) {
105         writer.println("*AudioControlWrapperV1*");
106         writer.println("Supported Features - none");
107     }
108 
109     @Override
setFadeTowardFront(float value)110     public void setFadeTowardFront(float value) {
111         try {
112             mAudioControlV1.setFadeTowardFront(value);
113         } catch (RemoteException e) {
114             Slogf.e(TAG, "setFadeTowardFront failed", e);
115         }
116     }
117 
118     @Override
setBalanceTowardRight(float value)119     public void setBalanceTowardRight(float value) {
120         try {
121             mAudioControlV1.setBalanceTowardRight(value);
122         } catch (RemoteException e) {
123             Slogf.e(TAG, "setBalanceTowardRight failed", e);
124         }
125     }
126 
127     @Override
onDevicesToDuckChange(List<CarDuckingInfo> carDuckingInfos)128     public void onDevicesToDuckChange(List<CarDuckingInfo> carDuckingInfos) {
129         throw new UnsupportedOperationException("HAL ducking is unsupported for IAudioControl@1.0");
130     }
131 
132     @Override
onDevicesToMuteChange(@onNull List<MutingInfo> carZonesMutingInfo)133     public void onDevicesToMuteChange(@NonNull List<MutingInfo> carZonesMutingInfo) {
134         throw new UnsupportedOperationException("HAL muting is unsupported for IAudioControl@1.0");
135     }
136 
137     @Override
setModuleChangeCallback(HalAudioModuleChangeCallback moduleChangeCallback)138     public void setModuleChangeCallback(HalAudioModuleChangeCallback moduleChangeCallback) {
139         throw new UnsupportedOperationException("Module change callback is unsupported for"
140                 + " IAudioControl@1.0");
141     }
142 
143     @Override
clearModuleChangeCallback()144     public void clearModuleChangeCallback() {
145         throw new UnsupportedOperationException("Module change callback is unsupported for"
146                 + " IAudioControl@1.0");
147     }
148 
149     /**
150      * Gets the bus associated with CarAudioContext.
151      *
152      * <p>This API is used along with car_volume_groups.xml to configure volume groups and routing.
153      *
154      * @param audioContext {@code CarAudioContext} to get a context for.
155      * @return int bus number. Should be part of the prefix for the device's address. For example,
156      * bus001_media would be bus 1.
157      * @deprecated Volume and routing configuration has been replaced by
158      * car_audio_configuration.xml. Starting with IAudioControl@V2.0, getBusForContext is no longer
159      * supported.
160      */
161     @Deprecated
getBusForContext(@arAudioContext.AudioContext int audioContext)162     public int getBusForContext(@CarAudioContext.AudioContext int audioContext) {
163         try {
164             return mAudioControlV1.getBusForContext(audioContext);
165         } catch (RemoteException e) {
166             Slogf.e(TAG, "Failed to query IAudioControl HAL to get bus for context", e);
167             throw new IllegalStateException("Failed to query IAudioControl#getBusForContext", e);
168         }
169     }
170 
171     @Override
linkToDeath(@ullable AudioControlDeathRecipient deathRecipient)172     public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
173         try {
174             mAudioControlV1.linkToDeath(this::serviceDied, 0);
175             mDeathRecipient = deathRecipient;
176         } catch (RemoteException e) {
177             throw new IllegalStateException("Call to IAudioControl@1.0#linkToDeath failed", e);
178         }
179     }
180 
181     @Override
unlinkToDeath()182     public void unlinkToDeath() {
183         try {
184             mAudioControlV1.unlinkToDeath(this::serviceDied);
185             mDeathRecipient = null;
186         } catch (RemoteException e) {
187             throw new IllegalStateException("Call to IAudioControl@1.0#unlinkToDeath failed", e);
188         }
189     }
190 
serviceDied(long cookie)191     private void serviceDied(long cookie) {
192         Slogf.w(TAG, "IAudioControl@1.0 died. Fetching new handle");
193         mAudioControlV1 = AudioControlWrapperV1.getService();
194         linkToDeath(mDeathRecipient);
195         if (mDeathRecipient != null) {
196             mDeathRecipient.serviceDied();
197         }
198     }
199 
200 
201 }
202