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