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