• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING;
20 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
21 
22 import android.annotation.NonNull;
23 import android.hardware.automotive.audiocontrol.MutingInfo;
24 import android.util.IndentingPrintWriter;
25 import android.util.Log;
26 import android.util.Slog;
27 import android.util.SparseArray;
28 
29 import com.android.car.CarLog;
30 import com.android.car.audio.hal.AudioControlWrapper;
31 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
32 import com.android.internal.annotations.GuardedBy;
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.internal.util.Preconditions;
35 
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.Objects;
39 
40 final class CarVolumeGroupMuting {
41 
42     private static final String TAG = CarLog.tagFor(CarVolumeGroupMuting.class);
43 
44     private final SparseArray<CarAudioZone> mCarAudioZones;
45     private final AudioControlWrapper mAudioControlWrapper;
46     private final Object mLock = new Object();
47     @GuardedBy("mLock")
48     private List<MutingInfo> mLastMutingInformation;
49     @GuardedBy("mLock")
50     private boolean mIsMutingRestricted;
51 
CarVolumeGroupMuting(@onNull SparseArray<CarAudioZone> carAudioZones, @NonNull AudioControlWrapper audioControlWrapper)52     CarVolumeGroupMuting(@NonNull SparseArray<CarAudioZone> carAudioZones,
53             @NonNull AudioControlWrapper audioControlWrapper) {
54         mCarAudioZones = Objects.requireNonNull(carAudioZones, "Car Audio Zones can not be null");
55         Preconditions.checkArgument(carAudioZones.size() != 0,
56                 "At least one car audio zone must be present.");
57         mAudioControlWrapper = Objects.requireNonNull(audioControlWrapper,
58                 "Audio Control Wrapper can not be null");
59         requireGroupMutingSupported(audioControlWrapper);
60         mLastMutingInformation = new ArrayList<>();
61     }
62 
requireGroupMutingSupported(AudioControlWrapper audioControlWrapper)63     private static void requireGroupMutingSupported(AudioControlWrapper audioControlWrapper) {
64         if (audioControlWrapper
65                 .supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING)) {
66             return;
67         }
68         throw new IllegalStateException("audioUseCarVolumeGroupMuting is enabled but "
69                 + "IAudioControl HAL does not support volume group muting");
70     }
71 
72     /**
73      * Signal that mute has changed.
74      */
carMuteChanged()75     public void carMuteChanged() {
76         if (Log.isLoggable(TAG, Log.DEBUG)) {
77             Slog.d(TAG, "carMuteChanged");
78         }
79 
80         List<MutingInfo> mutingInfo = generateMutingInfo();
81         setLastMutingInfo(mutingInfo);
82         mAudioControlWrapper.onDevicesToMuteChange(mutingInfo);
83     }
84 
setRestrictMuting(boolean isMutingRestricted)85     public void setRestrictMuting(boolean isMutingRestricted) {
86         synchronized (mLock) {
87             mIsMutingRestricted = isMutingRestricted;
88         }
89 
90         carMuteChanged();
91     }
92 
isMutingRestricted()93     private boolean isMutingRestricted() {
94         synchronized (mLock) {
95             return mIsMutingRestricted;
96         }
97     }
98 
setLastMutingInfo(List<MutingInfo> mutingInfo)99     private void setLastMutingInfo(List<MutingInfo> mutingInfo) {
100         synchronized (mLock) {
101             mLastMutingInformation = mutingInfo;
102         }
103     }
104 
105     @VisibleForTesting
getLastMutingInformation()106     List<MutingInfo> getLastMutingInformation() {
107         synchronized (mLock) {
108             return mLastMutingInformation;
109         }
110     }
111 
generateMutingInfo()112     private List<MutingInfo> generateMutingInfo() {
113         List<MutingInfo> mutingInformation = new ArrayList<>(mCarAudioZones.size());
114 
115         boolean isMutingRestricted = isMutingRestricted();
116         for (int index = 0; index < mCarAudioZones.size(); index++) {
117             mutingInformation.add(generateMutingInfoFromZone(mCarAudioZones.valueAt(index),
118                     isMutingRestricted));
119         }
120 
121         return mutingInformation;
122     }
123 
124     /**
125      * Dumps internal state
126      */
127     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)128     public void dump(IndentingPrintWriter writer) {
129         writer.println(TAG);
130         writer.increaseIndent();
131         synchronized (mLock) {
132             writer.printf("Is muting restricted? %b\n", mIsMutingRestricted);
133             for (int index = 0; index < mLastMutingInformation.size(); index++) {
134                 dumpCarMutingInfo(writer, mLastMutingInformation.get(index));
135             }
136         }
137         writer.decreaseIndent();
138     }
139 
dumpCarMutingInfo(IndentingPrintWriter writer, MutingInfo info)140     private void dumpCarMutingInfo(IndentingPrintWriter writer, MutingInfo info) {
141         writer.printf("Zone ID: %d\n", info.zoneId);
142 
143         writer.println("Muted Devices:");
144         writer.increaseIndent();
145         dumpDeviceAddresses(writer, info.deviceAddressesToMute);
146         writer.decreaseIndent();
147 
148         writer.println("Un-muted Devices:");
149         writer.increaseIndent();
150         dumpDeviceAddresses(writer, info.deviceAddressesToUnmute);
151         writer.decreaseIndent();
152     }
153 
dumpDeviceAddresses(IndentingPrintWriter writer, String[] devices)154     private static void dumpDeviceAddresses(IndentingPrintWriter writer, String[] devices) {
155         for (int index = 0; index < devices.length; index++) {
156             writer.printf("%d %s\n", index, devices[index]);
157         }
158     }
159 
160     @VisibleForTesting
generateMutingInfoFromZone(CarAudioZone audioZone, boolean isMutingRestricted)161     static MutingInfo generateMutingInfoFromZone(CarAudioZone audioZone,
162             boolean isMutingRestricted) {
163         MutingInfo mutingInfo = new MutingInfo();
164         mutingInfo.zoneId = audioZone.getId();
165 
166         List<String> mutedDevices = new ArrayList<>();
167         List<String> unMutedDevices = new ArrayList<>();
168         CarVolumeGroup[] groups = audioZone.getVolumeGroups();
169 
170         for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
171             CarVolumeGroup group = groups[groupIndex];
172 
173             if (group.isMuted() || (isMutingRestricted && !group.hasCriticalAudioContexts())) {
174                 mutedDevices.addAll(group.getAddresses());
175             } else {
176                 unMutedDevices.addAll(group.getAddresses());
177             }
178         }
179 
180         mutingInfo.deviceAddressesToMute = mutedDevices.toArray(new String[mutedDevices.size()]);
181         mutingInfo.deviceAddressesToUnmute =
182                 unMutedDevices.toArray(new String[unMutedDevices.size()]);
183 
184         return mutingInfo;
185     }
186 }
187