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