1 /* 2 * Copyright (C) 2017 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.cts.verifier.audio.peripheralprofile; 18 19 import android.os.Environment; 20 import androidx.annotation.Nullable; 21 import android.util.Log; 22 import android.util.Xml; 23 24 import org.xml.sax.Attributes; 25 import org.xml.sax.InputSource; 26 import org.xml.sax.SAXException; 27 import org.xml.sax.XMLReader; 28 import org.xml.sax.helpers.DefaultHandler; 29 30 import java.io.ByteArrayInputStream; 31 import java.io.File; 32 import java.io.FileInputStream; 33 import java.io.FileNotFoundException; 34 import java.io.FileWriter; 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.util.ArrayList; 38 39 import javax.xml.parsers.ParserConfigurationException; 40 import javax.xml.parsers.SAXParser; 41 import javax.xml.parsers.SAXParserFactory; 42 43 public class ProfileManager { 44 private static final String TAG = "ProfileManager"; 45 private static final boolean DEBUG = false; 46 47 private static final String mBuiltInprofiles = 48 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" + 49 "<ProfileList Version=\"1.0.0\">" + 50 "<PeripheralProfile ProfileName=\"AudioBox USB 96\" ProfileDescription=\"PreSonus AudioBox USB 96\" ProductName=\"USB-Audio - AudioBox USB 96\">" + 51 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" + 52 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" + 53 "</PeripheralProfile>" + 54 "<PeripheralProfile ProfileName=\"AudioBox 44VSL\" ProfileDescription=\"Presonus AudioBox 44VSL\" ProductName=\"USB-Audio - AudioBox 44 VSL\">" + 55 "<OutputDevInfo ChanCounts=\"2,3,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"3,7,15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" + 56 "<InputDevInfo ChanCounts=\"1,2,3,4\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3,7,15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" + 57 "</PeripheralProfile>" + 58 "<PeripheralProfile ProfileName=\"AudioBox 22VSL\" ProfileDescription=\"Presonus AudioBox 22VSL\" ProductName=\"USB-Audio - AudioBox 22 VSL\">" + 59 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" + 60 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" + 61 "</PeripheralProfile>" + 62 "<PeripheralProfile ProfileName=\"AudioBox USB\" ProfileDescription=\"Presonus AudioBox USB\" ProductName=\"USB-Audio - AudioBox USB\">" + 63 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" + 64 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" + 65 "</PeripheralProfile>" + 66 "<PeripheralProfile ProfileName=\"Focusrite 2i4\" ProfileDescription=\"Focusrite Scarlett 2i4\" ProductName=\"USB-Audio - Scarlett 2i4 USB\">" + 67 "<OutputDevInfo ChanCounts=\"2,3,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"3,7,15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" + 68 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" + 69 "</PeripheralProfile>" + 70 "<PeripheralProfile ProfileName=\"Behringer UMC204HD\" ProfileDescription=\"Behringer UMC204HD\" ProductName=\"USB-Audio - UMC204HD 192k\">" + 71 "<OutputDevInfo ChanCounts=\"2,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"15\" Encodings=\"2,4\" SampleRates=\"44100,48000,88200,96000,176400,192000\"/>" + 72 "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000,176400,192000\"/>" + 73 "</PeripheralProfile>" + 74 "<PeripheralProfile ProfileName=\"Roland Rubix24\" ProfileDescription=\"Roland Rubix24\" ProductName=\"USB-Audio - Rubix24\">" + 75 "<OutputDevInfo ChanCounts=\"2,3,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"3,7,15\" Encodings=\"4\" SampleRates=\"44100,48000,96000,192000\"/>" + 76 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,96000,192000\"/>" + 77 "</PeripheralProfile>" + 78 "<PeripheralProfile ProfileName=\"Pixel USB-C Dongle + Wired Analog Headset\" ProfileDescription=\"Reference USB Dongle\" ProductName=\"USB-Audio - USB-C to 3.5mm-Headphone Adapte\">" + 79 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\" />" + 80 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\" />" + 81 "<ButtonInfo HasBtnA=\"1\" HasBtnB=\"1\" HasBtnC=\"1\" />" + 82 "</PeripheralProfile>" + 83 "<PeripheralProfile ProfileName=\"HTC Dongle\" ProfileDescription=\"Type-C to 3.5mm Headphone\" ProductName=\"USB-Audio - HTC Type-C to 3.5mm Headphone J\">" + 84 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\" />" + 85 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\"/>" + 86 "<ButtonInfo HasBtnA=\"1\" HasBtnB=\"1\" HasBtnC=\"1\" />" + 87 "</PeripheralProfile>" + 88 "<PeripheralProfile ProfileName=\"JBL Reflect Aware\" ProfileDescription=\"JBL Reflect Aware\" ProductName=\"USB-Audio - JBL Reflect Aware\">" + 89 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"2\" SampleRates=\"44100,48000\" />" + 90 "<InputDevInfo ChanCounts=\"1\" ChanPosMasks=\"16\" ChanIndexMasks=\"1\" Encodings=\"2\" SampleRates=\"44100,48000\" />" + 91 "<ButtonInfo HasBtnA=\"1\" HasBtnB=\"1\" HasBtnC=\"1\" />" + 92 "</PeripheralProfile>" + 93 "<PeripheralProfile ProfileName=\"Libratone Q Adapt\" ProfileDescription=\"Libratone Q Adapt Headset\" ProductName=\"USB-Audio - Libratone_INEAR\">" + 94 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"2\" SampleRates=\"48000\" />" + 95 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1\" Encodings=\"2\" SampleRates=\"48000\" />"+ 96 "<ButtonInfo HasBtnA=\"1\" HasBtnB=\"1\" HasBtnC=\"1\" />" + 97 "</PeripheralProfile>" + 98 "</ProfileList>"; 99 100 // XML Tags and Attributes 101 private final static String kTag_ProfileList = "ProfileList"; 102 private final static String kAttrName_Version = "Version"; 103 private final static String kValueStr_Version = "1.0.0"; 104 105 private final ArrayList<PeripheralProfile> mProfiles = 106 new ArrayList<PeripheralProfile>(); 107 108 private PeripheralProfile mParsingProfile = null; 109 addProfile(PeripheralProfile profile)110 public boolean addProfile(PeripheralProfile profile) { 111 mProfiles.add(profile); 112 113 return true; 114 } 115 116 private class ProfileLoader extends DefaultHandler { 117 @Override startElement(String namespaceURI, String localName, String qName, Attributes atts)118 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 119 if (localName.equals(kTag_ProfileList)) { 120 // Maybe check the version here. 121 } else if (localName.equals(PeripheralProfile.kTag_Profile)){ 122 mParsingProfile = new PeripheralProfile(null, null, null, null, null); 123 mParsingProfile.startElement(namespaceURI, localName, qName, atts); 124 } else { 125 mParsingProfile.startElement(namespaceURI, localName, qName, atts); 126 } 127 } 128 129 @Override endElement(String uri, String localName, String qName)130 public void endElement(String uri, String localName, String qName) { 131 if (localName.equals(kTag_ProfileList)) { 132 // Version Checking here maybe? 133 } else if (localName.equals(PeripheralProfile.kTag_Profile)){ 134 mProfiles.add(mParsingProfile); 135 mParsingProfile = null; 136 } 137 } 138 } 139 140 @Override toString()141 public String toString() { 142 return super.toString(); 143 } 144 loadProfiles(InputStream inStream)145 public boolean loadProfiles(InputStream inStream) { 146 SAXParserFactory spf = SAXParserFactory.newInstance(); 147 SAXParser sp; 148 try { 149 sp = spf.newSAXParser(); 150 XMLReader xr = sp.getXMLReader(); 151 xr.setContentHandler(new ProfileLoader()); 152 xr.parse(new InputSource(inStream)); 153 } catch (ParserConfigurationException e) { 154 e.printStackTrace(); 155 } catch (SAXException e) { 156 e.printStackTrace(); 157 } catch (IOException e) { 158 e.printStackTrace(); 159 } 160 161 return true; 162 } 163 loadProfiles(String profilesXML)164 public boolean loadProfiles(String profilesXML) { 165 mProfiles.clear(); 166 167 return loadProfiles(new ByteArrayInputStream(profilesXML.getBytes())); 168 } 169 loadProfiles()170 public boolean loadProfiles() { 171 return loadProfiles(mBuiltInprofiles); 172 } 173 174 // 175 // Access 176 // getProfiles()177 public ArrayList<PeripheralProfile> getProfiles() { return mProfiles; } 178 getNumProfiles()179 public int getNumProfiles() { 180 return mProfiles.size(); 181 } getProfile(int index)182 public PeripheralProfile getProfile(int index) { 183 return mProfiles.get(index); 184 } 185 186 @Nullable getProfile(String productName)187 public PeripheralProfile getProfile(String productName) { 188 for(PeripheralProfile profile : mProfiles) { 189 if (productName.equals(profile.getProductName())) { 190 return profile; 191 } 192 } 193 return null; 194 } 195 } 196