1 /*
2  * Copyright (C) 2021 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;
18 
19 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
20 import static android.util.Log.DEBUG;
21 import static android.util.Log.VERBOSE;
22 
23 import static com.android.car.CarLog.TAG_AUDIO;
24 
25 import android.annotation.NonNull;
26 import android.media.AudioManager;
27 import android.media.audiopolicy.AudioPolicy;
28 import android.media.audiopolicy.AudioPolicy.Builder;
29 import android.util.Log;
30 import android.util.Slog;
31 
32 import com.android.car.audio.CarAudioContext.AudioContext;
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.server.utils.Slogf;
35 
36 
37 import java.util.Objects;
38 
39 final class CarAudioPolicyVolumeCallback extends AudioPolicy.AudioPolicyVolumeCallback{
40     private final CarAudioService mCarAudioService;
41     private final AudioManager mAudioManager;
42     private final boolean mUseCarVolumeGroupMuting;
43 
addVolumeCallbackToPolicy(@onNull Builder policyBuilder, @NonNull CarAudioService carAudioService, @NonNull AudioManager audioManager, boolean useCarVolumeGroupMuting)44     static void addVolumeCallbackToPolicy(@NonNull Builder policyBuilder,
45             @NonNull CarAudioService carAudioService,
46             @NonNull AudioManager audioManager, boolean useCarVolumeGroupMuting) {
47         Objects.requireNonNull(policyBuilder, "AudioPolicy.Builder cannot be null");
48         policyBuilder.setAudioPolicyVolumeCallback(
49                 new CarAudioPolicyVolumeCallback(carAudioService, audioManager,
50                         useCarVolumeGroupMuting));
51         if (Log.isLoggable(TAG_AUDIO, DEBUG)) {
52             Slog.d(TAG_AUDIO, "Registered car audio policy volume callback");
53         }
54     }
55 
56     @VisibleForTesting
CarAudioPolicyVolumeCallback(@onNull CarAudioService carAudioService, @NonNull AudioManager audioManager, boolean useCarVolumeGroupMuting)57     CarAudioPolicyVolumeCallback(@NonNull CarAudioService carAudioService,
58             @NonNull AudioManager audioManager, boolean useCarVolumeGroupMuting) {
59         mCarAudioService = Objects.requireNonNull(carAudioService,
60                 "CarAudioService cannot be null");
61         mAudioManager = Objects.requireNonNull(audioManager, "AudioManager cannot be null");
62         mUseCarVolumeGroupMuting = useCarVolumeGroupMuting;
63     }
64 
65     @Override
onVolumeAdjustment(int adjustment)66     public void onVolumeAdjustment(int adjustment) {
67         @AudioContext int suggestedContext = mCarAudioService
68                 .getSuggestedAudioContextForPrimaryZone();
69 
70         int zoneId = PRIMARY_AUDIO_ZONE;
71         int groupId = mCarAudioService.getVolumeGroupIdForAudioContext(zoneId, suggestedContext);
72         boolean isMuted = isMuted(zoneId, groupId);
73 
74         if (Slogf.isLoggable(TAG_AUDIO, VERBOSE)) {
75             Slogf.v(TAG_AUDIO, "onVolumeAdjustment: "
76                     + AudioManager.adjustToString(adjustment) + " suggested audio context: "
77                     + CarAudioContext.toString(suggestedContext) + " suggested volume group: "
78                     + groupId + " is muted " + isMuted);
79         }
80 
81         final int currentVolume = mCarAudioService.getGroupVolume(zoneId, groupId);
82         final int flags = AudioManager.FLAG_FROM_KEY | AudioManager.FLAG_SHOW_UI;
83         int minGain = mCarAudioService.getGroupMinVolume(zoneId, groupId);
84         switch (adjustment) {
85             case AudioManager.ADJUST_LOWER:
86                 int minValue = Math.max(currentVolume - 1, minGain);
87                 if (isMuted)  {
88                     minValue = minGain;
89                 }
90                 mCarAudioService.setGroupVolume(zoneId, groupId, minValue, flags);
91                 break;
92             case AudioManager.ADJUST_RAISE:
93                 int maxValue = Math.min(currentVolume + 1,
94                         mCarAudioService.getGroupMaxVolume(zoneId, groupId));
95                 if (isMuted)  {
96                     maxValue = minGain;
97                 }
98                 mCarAudioService.setGroupVolume(zoneId, groupId, maxValue, flags);
99                 break;
100             case AudioManager.ADJUST_MUTE:
101             case AudioManager.ADJUST_UNMUTE:
102                 setMute(adjustment == AudioManager.ADJUST_MUTE, groupId, flags);
103                 break;
104             case AudioManager.ADJUST_TOGGLE_MUTE:
105                 setMute(!isMuted, groupId, flags);
106                 break;
107             case AudioManager.ADJUST_SAME:
108             default:
109                 break;
110         }
111     }
112 
isMuted(int zoneId, int groupId)113     private boolean isMuted(int zoneId, int groupId) {
114         if (mUseCarVolumeGroupMuting) {
115             return mCarAudioService.isVolumeGroupMuted(zoneId, groupId);
116         }
117         return mAudioManager.isMasterMute();
118     }
119 
setMute(boolean mute, int groupId, int flags)120     private void setMute(boolean mute, int groupId, int flags) {
121         if (mUseCarVolumeGroupMuting) {
122             mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, mute, flags);
123             return;
124         }
125         mCarAudioService.setMasterMute(mute, flags);
126     }
127 }
128