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 android.hardware.automotive.audiocontrol.V2_0.IAudioControl; 20 import android.hardware.automotive.audiocontrol.V2_0.ICloseHandle; 21 import android.hardware.automotive.audiocontrol.V2_0.IFocusListener; 22 import android.media.AudioAttributes; 23 import android.media.AudioAttributes.AttributeUsage; 24 import android.os.RemoteException; 25 import android.util.Log; 26 27 import androidx.annotation.Nullable; 28 29 import java.io.PrintWriter; 30 import java.util.NoSuchElementException; 31 import java.util.Objects; 32 33 /** 34 * Wrapper for IAudioControl@2.0. 35 */ 36 public final class AudioControlWrapperV2 implements AudioControlWrapper { 37 private static final String TAG = AudioControlWrapperV2.class.getSimpleName(); 38 39 private IAudioControl mAudioControlV2; 40 41 private AudioControlDeathRecipient mDeathRecipient; 42 private ICloseHandle mCloseHandle; 43 getService()44 public static @Nullable IAudioControl getService() { 45 try { 46 return IAudioControl.getService(true); 47 } catch (RemoteException e) { 48 throw new IllegalStateException("Failed to get IAudioControl@2.0 service", e); 49 } catch (NoSuchElementException e) { 50 return null; 51 } 52 } 53 AudioControlWrapperV2(IAudioControl audioControlV2)54 AudioControlWrapperV2(IAudioControl audioControlV2) { 55 mAudioControlV2 = Objects.requireNonNull(audioControlV2); 56 } 57 58 @Override unregisterFocusListener()59 public void unregisterFocusListener() { 60 if (mCloseHandle != null) { 61 try { 62 mCloseHandle.close(); 63 } catch (RemoteException e) { 64 Log.e(TAG, "Failed to close focus listener", e); 65 } finally { 66 mCloseHandle = null; 67 } 68 } 69 } 70 71 @Override supportsHalAudioFocus()72 public boolean supportsHalAudioFocus() { 73 return true; 74 } 75 76 @Override registerFocusListener(IFocusListener focusListener)77 public void registerFocusListener(IFocusListener focusListener) { 78 Log.d(TAG, "Registering focus listener on AudioControl HAL"); 79 try { 80 mCloseHandle = mAudioControlV2.registerFocusListener(focusListener); 81 } catch (RemoteException e) { 82 Log.e(TAG, "Failed to register focus listener"); 83 throw new IllegalStateException("IAudioControl#registerFocusListener failed", e); 84 } 85 } 86 87 @Override onAudioFocusChange(@ttributeUsage int usage, int zoneId, int focusChange)88 public void onAudioFocusChange(@AttributeUsage int usage, int zoneId, int focusChange) { 89 if (Log.isLoggable(TAG, Log.DEBUG)) { 90 Log.d(TAG, "onAudioFocusChange: usage " + AudioAttributes.usageToString(usage) 91 + ", zoneId " + zoneId + ", focusChange " + focusChange); 92 } 93 try { 94 mAudioControlV2.onAudioFocusChange(usage, zoneId, focusChange); 95 } catch (RemoteException e) { 96 throw new IllegalStateException("Failed to query IAudioControl#onAudioFocusChange", e); 97 } 98 } 99 100 /** 101 * Dumps the current state of the {@code AudioControlWrapperV2}. 102 * 103 * @param indent indent to append to each new line. 104 * @param writer stream to write current state. 105 */ 106 @Override dump(String indent, PrintWriter writer)107 public void dump(String indent, PrintWriter writer) { 108 writer.printf("%s*AudioControlWrapperV2*\n", indent); 109 writer.printf("%s\tFocus listener registered on HAL? %b", indent, (mCloseHandle != null)); 110 } 111 112 @Override setFadeTowardFront(float value)113 public void setFadeTowardFront(float value) { 114 try { 115 mAudioControlV2.setFadeTowardFront(value); 116 } catch (RemoteException e) { 117 Log.e(TAG, "setFadeTowardFront failed", e); 118 } 119 } 120 121 @Override setBalanceTowardRight(float value)122 public void setBalanceTowardRight(float value) { 123 try { 124 mAudioControlV2.setBalanceTowardRight(value); 125 } catch (RemoteException e) { 126 Log.e(TAG, "setBalanceTowardRight failed", e); 127 } 128 } 129 130 @Override linkToDeath(@ullable AudioControlDeathRecipient deathRecipient)131 public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) { 132 try { 133 mAudioControlV2.linkToDeath(this::serviceDied, 0); 134 mDeathRecipient = deathRecipient; 135 } catch (RemoteException e) { 136 throw new IllegalStateException("Call to IAudioControl@2.0#linkToDeath failed", e); 137 } 138 } 139 140 @Override unlinkToDeath()141 public void unlinkToDeath() { 142 try { 143 mAudioControlV2.unlinkToDeath(this::serviceDied); 144 mDeathRecipient = null; 145 } catch (RemoteException e) { 146 throw new IllegalStateException("Call to IAudioControl@2.0#unlinkToDeath failed", e); 147 } 148 } 149 serviceDied(long cookie)150 private void serviceDied(long cookie) { 151 Log.w(TAG, "IAudioControl@2.0 died. Fetching new handle"); 152 mAudioControlV2 = AudioControlWrapperV2.getService(); 153 linkToDeath(mDeathRecipient); 154 if (mDeathRecipient != null) { 155 mDeathRecipient.serviceDied(); 156 } 157 } 158 } 159