1 package com.android.cts.verifier.audio; 2 3 import android.media.AudioManager; 4 import android.media.AudioTrack; 5 6 import java.util.ArrayList; 7 import java.util.Random; 8 9 /** 10 * This class stores common constants and methods. 11 */ 12 public class Common { 13 14 // Internal version code for tracking small changes. 15 // Format is a monotonic decimal number with Mmmpp 16 // M = major version 17 // mm = minor version 18 // pp = patch 19 public static final int VERSION_CODE = 10102; 20 // Key for storing in a protobuf. 21 public static final String KEY_VERSION_CODE = "version_code"; 22 23 public static final int RECORDING_SAMPLE_RATE_HZ 24 = AudioRecordHelper.getInstance().getSampleRate(); 25 public static final int PLAYING_SAMPLE_RATE_HZ 26 = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); 27 28 // Default constants. 29 public static final double PASSING_THRESHOLD_DB = -40.0; 30 public static final double PIP_DURATION_S = 0.004; 31 public static final double PAUSE_DURATION_S = 0.016; 32 public static final int PREFIX_NUM_CHIPS = 1023; 33 public static final int PREFIX_SAMPLES_PER_CHIP = 4; 34 public static final double PREFIX_LENGTH_S = 0.1; 35 public static final double PAUSE_BEFORE_PREFIX_DURATION_S = 0.5; 36 public static final double PAUSE_AFTER_PREFIX_DURATION_S = 0.4; 37 public static final double MIN_FREQUENCY_HZ = 500; 38 public static final double MAX_FREQUENCY_HZ = 21000; 39 public static final double FREQUENCY_STEP_HZ = 100; 40 public static final int SIGNAL_MIN_STRENGTH_DB_ABOVE_NOISE = 10; 41 public static final int REPETITIONS = 5; 42 public static final int NOISE_SAMPLES = 3; 43 44 public static final double[] FREQUENCIES_ORIGINAL = originalFrequencies(); 45 public static final int PIP_NUM = FREQUENCIES_ORIGINAL.length; 46 public static final int[] ORDER = order(); 47 public static final double[] FREQUENCIES = frequencies(); 48 49 public static final double[] WINDOW_FOR_RECORDER = 50 hann(Util.toLength(PIP_DURATION_S, RECORDING_SAMPLE_RATE_HZ)); 51 public static final double[] WINDOW_FOR_PLAYER = 52 hann(Util.toLength(PIP_DURATION_S, PLAYING_SAMPLE_RATE_HZ)); 53 54 public static final double[] PREFIX_FOR_RECORDER = prefix(RECORDING_SAMPLE_RATE_HZ); 55 public static final double[] PREFIX_FOR_PLAYER = prefix(PLAYING_SAMPLE_RATE_HZ); 56 57 /** 58 * Get a Hann window. 59 */ hann(int windowWidth)60 private static double[] hann(int windowWidth) { 61 double[] envelopeArray = new double[windowWidth]; 62 for (int i = 0; i < windowWidth; i++) { 63 envelopeArray[i] = 0.5 64 * (1 - Math.cos(2 * Math.PI * i / windowWidth)); 65 } 66 return envelopeArray; 67 } 68 69 /** 70 * Get a maximum length sequence, used as prefix to indicate start of signal. 71 */ prefix(int rate)72 private static double[] prefix(int rate) { 73 double[] codeSequence = new double[PREFIX_NUM_CHIPS]; 74 for (int i = 0; i < PREFIX_NUM_CHIPS; i++) { 75 if (i < 10) { 76 codeSequence[i] = 1; 77 } else { 78 codeSequence[i] = -codeSequence[i - 6] * codeSequence[i - 7] 79 * codeSequence[i - 9] * codeSequence[i - 10]; 80 } 81 } 82 double[] prefixArray = new double[PREFIX_NUM_CHIPS * PREFIX_SAMPLES_PER_CHIP]; 83 int offset = 0; 84 for (int i = 0; i < PREFIX_NUM_CHIPS; i++) { 85 double value = codeSequence[i]; 86 for (int j = 0; j < PREFIX_SAMPLES_PER_CHIP; j++) { 87 prefixArray[offset + j] = value; 88 } 89 offset += PREFIX_SAMPLES_PER_CHIP; 90 } 91 int prefixLength = (int) Math.round(PREFIX_LENGTH_S * rate); 92 double[] samplePrefixArray = new double[prefixLength]; 93 for (int i = 0; i < prefixLength; i++) { 94 double index = (double) i / prefixLength * (prefixArray.length - 1); 95 samplePrefixArray[i] = (1 - index + Math.floor(index)) * prefixArray[(int) Math.floor(index)] 96 + (1 + index - Math.ceil(index)) * prefixArray[(int) Math.ceil(index)]; 97 } 98 return samplePrefixArray; 99 } 100 101 /** 102 * Returns array consists the frequencies of the test pips in the order that will be used in test. 103 */ frequencies()104 private static double[] frequencies() { 105 double[] originalFrequencies = originalFrequencies(); 106 107 double[] randomFrequencies = new double[Common.REPETITIONS * originalFrequencies.length]; 108 for (int i = 0; i < REPETITIONS * originalFrequencies.length; i++) { 109 randomFrequencies[i] = originalFrequencies[ORDER[i] % originalFrequencies.length]; 110 } 111 112 return randomFrequencies; 113 } 114 115 /** 116 * Returns array consists the frequencies of the test pips. 117 */ originalFrequencies()118 private static double[] originalFrequencies() { 119 ArrayList<Double> frequencies = new ArrayList<Double>(); 120 double frequency = Common.MIN_FREQUENCY_HZ; 121 while (frequency <= Common.MAX_FREQUENCY_HZ) { 122 frequencies.add(new Double(frequency)); 123 if ((frequency >= 18500) && (frequency < 20000)) { 124 frequency += Common.FREQUENCY_STEP_HZ; 125 } else { 126 frequency += Common.FREQUENCY_STEP_HZ * 10; 127 } 128 } 129 Double[] frequenciesArray = frequencies.toArray(new Double[frequencies.size()]); 130 double[] frequenciesPrimitiveArray = new double[frequenciesArray.length]; 131 for (int i = 0; i < frequenciesArray.length; i++) { 132 frequenciesPrimitiveArray[i] = frequenciesArray[i]; 133 } 134 return frequenciesPrimitiveArray; 135 } 136 137 /** 138 * Fisher-Yates shuffle. 139 */ order()140 private static int[] order() { 141 int[] order = new int[REPETITIONS * PIP_NUM]; 142 long seed = 0; 143 Random generator = new Random(seed); 144 for (int i = 0; i < REPETITIONS * PIP_NUM; i++) { 145 int j = generator.nextInt(i + 1); 146 order[i] = order[j]; 147 order[j] = i; 148 } 149 return order; 150 } 151 } 152