1 /*
2  * Copyright (C) 2019 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 package com.android.car.audio;
17 
18 
19 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
20 import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
21 
22 import android.media.AudioDeviceAttributes;
23 import android.util.SparseArray;
24 
25 import com.android.internal.util.Preconditions;
26 
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Set;
30 
31 final class CarAudioZonesValidator {
CarAudioZonesValidator()32     private CarAudioZonesValidator() {
33     }
34 
validate(SparseArray<CarAudioZone> carAudioZones)35     static void validate(SparseArray<CarAudioZone> carAudioZones) {
36         validateAtLeastOneZoneDefined(carAudioZones);
37         validateVolumeGroupsForEachZone(carAudioZones);
38         validateEachAddressAppearsAtMostOnce(carAudioZones);
39         validatePrimaryZoneHasInputDevice(carAudioZones);
40     }
41 
validatePrimaryZoneHasInputDevice(SparseArray<CarAudioZone> carAudioZones)42     private static void validatePrimaryZoneHasInputDevice(SparseArray<CarAudioZone> carAudioZones) {
43         CarAudioZone primaryZone = carAudioZones.get(PRIMARY_AUDIO_ZONE);
44         List<AudioDeviceAttributes> devices = primaryZone.getInputAudioDevices();
45         Preconditions.checkCollectionNotEmpty(devices, "Primary Zone Input Devices");
46         for (int index = 0; index < devices.size(); index++) {
47             AudioDeviceAttributes device = devices.get(index);
48             if (device.getType() == TYPE_BUILTIN_MIC) {
49                 return;
50             }
51         }
52         throw new RuntimeException("Primary Zone must have at least one microphone input device");
53     }
54 
validateAtLeastOneZoneDefined(SparseArray<CarAudioZone> carAudioZones)55     private static void validateAtLeastOneZoneDefined(SparseArray<CarAudioZone> carAudioZones) {
56         if (carAudioZones.size() == 0) {
57             throw new RuntimeException("At least one zone should be defined");
58         }
59     }
60 
validateVolumeGroupsForEachZone(SparseArray<CarAudioZone> carAudioZones)61     private static void validateVolumeGroupsForEachZone(SparseArray<CarAudioZone> carAudioZones) {
62         for (int i = 0; i < carAudioZones.size(); i++) {
63             CarAudioZone zone = carAudioZones.valueAt(i);
64             if (!zone.validateVolumeGroups()) {
65                 throw new RuntimeException(
66                         "Invalid volume groups configuration for zone " + zone.getId());
67             }
68         }
69     }
70 
validateEachAddressAppearsAtMostOnce( SparseArray<CarAudioZone> carAudioZones)71     private static void validateEachAddressAppearsAtMostOnce(
72             SparseArray<CarAudioZone> carAudioZones) {
73         Set<String> addresses = new HashSet<>();
74         for (int i = 0; i < carAudioZones.size(); i++) {
75             CarAudioZone zone = carAudioZones.valueAt(i);
76             for (CarVolumeGroup carVolumeGroup : zone.getVolumeGroups()) {
77                 for (String address : carVolumeGroup.getAddresses()) {
78                     if (!addresses.add(address)) {
79                         throw new RuntimeException("Device with address "
80                                 + address + " appears in multiple volume groups or audio zones");
81                     }
82                 }
83             }
84         }
85     }
86 }
87