• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 #include <cinttypes>
17 
18 #include "chre/util/macros.h"
19 #include "chre/util/nanoapp/log.h"
20 
21 #include <general_test/basic_audio_test.h>
22 
23 #include <shared/send_message.h>
24 #include <shared/time_util.h>
25 
26 #define LOG_TAG "[ChreBasicAudioTest]"
27 
28 using nanoapp_testing::kOneSecondInNanoseconds;
29 using nanoapp_testing::sendFatalFailureToHost;
30 using nanoapp_testing::sendSuccessToHost;
31 
32 namespace general_test {
33 namespace {
34 
35 //! This is a reasonably high limit on the number of audio sources that a system
36 //! would expose. Use this to verify that there are no gaps in the source
37 //! handles.
38 constexpr uint32_t kMaxAudioSources = 128;
39 
40 //! This is a reasonably high limit on the sample rate for a source that the
41 //! system would expose. Sampling rates above 96kHz are likely to be too high
42 //! for always-on low-power use-cases. Yes, this omits 192kHz, but that is
43 //! generally reserved for professional audio/recording and mixing applications.
44 //! Even 96kHz is a stretch, but capping it here allows room to grow. Expected
45 //! values are more like 16kHz.
46 constexpr uint32_t kMaxAudioSampleRate = 96000;
47 
48 //! Provide a floor for the sampling rate of an audio source that the system
49 //! would expose. Nyquist theorem dictates that the maximum frequency that can
50 //! be reproduced from given sequence of samples is equal to half that of the
51 //! sampling rate. This sets a lower bound to try to detect bugs or glitches.
52 constexpr uint32_t kMinAudioSampleRate = 4000;
53 
54 //! Provide a floor for buffer duration. This ensures that at the maximum
55 //! sample rate possible, a minimum number of samples will be delivered in
56 //! a batch.
57 constexpr uint64_t kMinBufferDuration =
58     (kOneSecondInNanoseconds / kMaxAudioSampleRate) * 10;
59 
60 //! Provide a ceiling for the maximum buffer duration. This is to catch buggy
61 //! descriptors of audio sources who expose very long buffers of data which are
62 //! not practical for always-on, low-power use-cases.
63 constexpr uint64_t kMaxBufferDuration = kOneSecondInNanoseconds * 120;
64 
65 //! While a variety of sample rates are supported, for the purposes of basic
66 //! audio data validation, we buffer about 4 seconds worth of PCM audio data
67 //! sampled at 16KHz.
68 constexpr uint32_t kRequiredSampleRate = 16000;
69 
70 /**
71  * @return true if the character is ASCII printable.
72  */
isAsciiPrintable(char c)73 bool isAsciiPrintable(char c) {
74   // A simple enough test to verify that a character is printable. These
75   // constants can be verified by reviewing an ASCII chart. All printable
76   // characters that we care about for CHRE lie between these two bounds and are
77   // contiguous.
78   return (c >= ' ' && c <= '~');
79 }
80 
81 /**
82  * @return true if the supplied string is printable, null-terminated and not
83  * longer than the supplied length (including null-terminator).
84  */
verifyStringWithLength(const char * str,size_t length)85 bool verifyStringWithLength(const char *str, size_t length) {
86   bool nullTerminatorFound = false;
87   bool isPrintable = true;
88   for (size_t i = 0; i < length; i++) {
89     if (str[i] == '\0') {
90       nullTerminatorFound = true;
91       break;
92     } else if (!isAsciiPrintable(str[i])) {
93       isPrintable = false;
94       break;
95     }
96   }
97 
98   return (isPrintable && nullTerminatorFound);
99 }
100 
101 /**
102  * Validates the fields of a chreAudioSource provided by the framework and posts
103  * a failure if the source descriptor is malformed.
104  *
105  * @return true if the source was valid.
106  */
validateAudioSource(uint32_t handle,const struct chreAudioSource & source)107 bool validateAudioSource(uint32_t handle,
108                          const struct chreAudioSource &source) {
109   bool valid = false;
110   if (!verifyStringWithLength(source.name, CHRE_AUDIO_SOURCE_NAME_MAX_SIZE)) {
111     sendFatalFailureToHost("Invalid audio source name for handle ", &handle);
112   } else if (source.sampleRate > kMaxAudioSampleRate ||
113              source.sampleRate < kMinAudioSampleRate) {
114     sendFatalFailureToHost("Invalid audio sample rate for handle ", &handle);
115   } else if (source.minBufferDuration < kMinBufferDuration ||
116              source.minBufferDuration > kMaxBufferDuration) {
117     sendFatalFailureToHost("Invalid min buffer duration for handle ", &handle);
118   } else if (source.maxBufferDuration < kMinBufferDuration ||
119              source.maxBufferDuration > kMaxBufferDuration) {
120     sendFatalFailureToHost("Invalid max buffer duration for handle ", &handle);
121   } else if (source.format != CHRE_AUDIO_DATA_FORMAT_8_BIT_U_LAW &&
122              source.format != CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM) {
123     sendFatalFailureToHost("Invalid audio format for handle ", &handle);
124   } else {
125     valid = true;
126   }
127 
128   return valid;
129 }
130 
validateMinimumAudioSource(const struct chreAudioSource & source)131 bool validateMinimumAudioSource(const struct chreAudioSource &source) {
132   // CHQTS requires a 16kHz, PCM-format, 2 second buffer.
133   constexpr uint64_t kRequiredBufferDuration = 2 * kOneSecondInNanoseconds;
134 
135   // Ensure that the minimum buffer size is less than or equal to the required
136   // size.
137   return (source.sampleRate == kRequiredSampleRate &&
138           source.minBufferDuration <= kRequiredBufferDuration &&
139           source.maxBufferDuration >= kRequiredBufferDuration &&
140           source.format == CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM);
141 }
142 
143 /**
144  * Attempts to query for all audio sources up to kMaxAudioSources and posts a
145  * failure if a gap is found in the handles or the provided descriptor is
146  * invalid.
147  */
validateAudioSources()148 void validateAudioSources() {
149   uint32_t validHandleCount = 0;
150   bool previousSourceFound = true;
151   bool minimumRequirementMet = false;
152   for (uint32_t handle = 0; handle < kMaxAudioSources; handle++) {
153     struct chreAudioSource audioSource;
154     bool sourceFound = chreAudioGetSource(handle, &audioSource);
155     if (sourceFound) {
156       validHandleCount++;
157       if (!previousSourceFound) {
158         sendFatalFailureToHost("Gap detected in audio handles at ", &handle);
159       } else {
160         bool valid = validateAudioSource(handle, audioSource);
161         if (valid && !minimumRequirementMet) {
162           minimumRequirementMet = validateMinimumAudioSource(audioSource);
163         }
164       }
165     }
166 
167     previousSourceFound = sourceFound;
168   }
169 
170   if (validHandleCount > 0) {
171     if (!minimumRequirementMet) {
172       sendFatalFailureToHost(
173           "Failed to meet minimum audio source requirements");
174     }
175 
176     if (validHandleCount == kMaxAudioSources) {
177       sendFatalFailureToHost("System is reporting too many audio sources");
178     }
179   }
180 }
181 
182 /**
183  * Attempts to request audio data from the default microphone handle (0),
184  * posts a failure if the data request failed
185  */
requestAudioData()186 void requestAudioData() {
187   constexpr uint32_t kAudioHandle = 0;
188   struct chreAudioSource audioSource;
189 
190   if (!chreAudioGetSource(kAudioHandle, &audioSource)) {
191     sendFatalFailureToHost("Failed to query source for handle 0");
192   } else if (!chreAudioConfigureSource(kAudioHandle, true /* enable */,
193                                        audioSource.minBufferDuration,
194                                        audioSource.minBufferDuration)) {
195     sendFatalFailureToHost("Failed to request audio data for handle 0");
196   }
197 }
198 
199 /**
200  * Check if the audio samples are all zeros
201  *
202  * @return true on check passing
203  */
checkSamplesAllZeros(const int16_t * data,const size_t dataLen)204 bool checkSamplesAllZeros(const int16_t *data, const size_t dataLen) {
205   for (size_t i = 0; i < dataLen; ++i) {
206     if (data[i] != 0) {
207       return true;
208     }
209   }
210   return false;
211 }
212 
213 /**
214  * Check if adjacent audio samples are unique
215  *
216  * @return true on check pass
217  */
checkSamplesAllSame(const int16_t * data,const size_t dataLen)218 bool checkSamplesAllSame(const int16_t *data, const size_t dataLen) {
219   if (dataLen > 0) {
220     const int16_t controlValue = data[0];
221     for (size_t i = 1; i < dataLen; ++i) {
222       if (data[i] != controlValue) {
223         return true;
224       }
225     }
226   }
227   return false;
228 }
229 
handleAudioDataEvent(const chreAudioDataEvent * dataEvent)230 void handleAudioDataEvent(const chreAudioDataEvent *dataEvent) {
231   constexpr uint32_t kAudioHandle = 0;
232 
233   // A count of the number of data events we've received - we stop
234   // the test after receiving 2 data events.
235   static uint8_t numDataEventsSoFar = 1;
236 
237   if (dataEvent == nullptr) {
238     sendFatalFailureToHost("Null event data");
239   } else if (dataEvent->samplesS16 == nullptr) {
240     sendFatalFailureToHost("Null audio data frame");
241   } else if (dataEvent->sampleCount == 0) {
242     sendFatalFailureToHost("0 samples in audio data frame");
243   } else {
244     struct chreAudioSource audioSource;
245     if (!chreAudioGetSource(kAudioHandle, &audioSource)) {
246       sendFatalFailureToHost("Failed to get audio source for handle 0");
247     } else {
248       // Per the CHRE Audio API requirements, it is expected that we exactly
249       // the number of samples that we ask for - we verify that here.
250       const auto kNumSamplesExpected =
251           static_cast<uint32_t>(audioSource.minBufferDuration *
252                                 kRequiredSampleRate / kOneSecondInNanoseconds);
253       if (dataEvent->sampleCount != kNumSamplesExpected) {
254         LOGE("Unexpected num samples - Expected: %" PRIu32 ", Actual: %" PRIu32,
255              kNumSamplesExpected, dataEvent->sampleCount);
256         uint32_t sampleCountDifference =
257             (kNumSamplesExpected > dataEvent->sampleCount)
258                 ? (kNumSamplesExpected - dataEvent->sampleCount)
259                 : (dataEvent->sampleCount - kNumSamplesExpected);
260         sendFatalFailureToHost("Unexpected number of samples received",
261                                &sampleCountDifference);
262       }
263     }
264   }
265 
266   if (!checkSamplesAllZeros(dataEvent->samplesS16, dataEvent->sampleCount)) {
267     sendFatalFailureToHost("All audio samples were zeros");
268   } else if (!checkSamplesAllSame(dataEvent->samplesS16,
269                                   dataEvent->sampleCount)) {
270     sendFatalFailureToHost("All audio samples were identical");
271   }
272 
273   if (numDataEventsSoFar == 2) {
274     if (!chreAudioConfigureSource(kAudioHandle, false /* enable */,
275                                   0 /* bufferDuration */,
276                                   0 /* deliveryInterval */)) {
277       sendFatalFailureToHost("Failed to disable audio source for handle 0");
278     } else {
279       sendSuccessToHost();
280     }
281   } else {
282     ++numDataEventsSoFar;
283   }
284 }
285 
isAudioSupported()286 bool isAudioSupported() {
287   struct chreAudioSource source;
288   constexpr uint32_t kRequiredAudioHandle = 0;
289   // If the DUT supports CHRE audio, then audio handle 0 is required to be
290   // valid. There is the risk that the chreAudioGetSource function might
291   // legitimately fail however - we should replace this function when CHRE
292   // audio capabilities in b/185155280 are implemented.
293   // TODO (b/185155280): fix this query
294   return chreAudioGetSource(kRequiredAudioHandle, &source);
295 }
296 }  // anonymous namespace
297 
BasicAudioTest()298 BasicAudioTest::BasicAudioTest()
299     : Test(CHRE_API_VERSION_1_2), mInMethod(false), mState(State::kPreStart) {}
300 
setUp(uint32_t messageSize,const void *)301 void BasicAudioTest::setUp(uint32_t messageSize, const void * /* message */) {
302   if (messageSize != 0) {
303     sendFatalFailureToHost("Beginning message expects 0 additional bytes, got ",
304                            &messageSize);
305   }
306 
307   if (!isAudioSupported()) {
308     sendSuccessToHost();
309 
310   } else {
311     validateAudioSources();
312 
313     mState = State::kExpectingAudioData;
314 
315     requestAudioData();
316   }
317 }
318 
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)319 void BasicAudioTest::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
320                                  const void *eventData) {
321   UNUSED_VAR(senderInstanceId);
322 
323   if (mInMethod) {
324     sendFatalFailureToHost("handleEvent() invoked while already in method.");
325   }
326 
327   mInMethod = true;
328 
329   if (mState == State::kPreStart) {
330     unexpectedEvent(eventType);
331   } else {
332     switch (eventType) {
333       case CHRE_EVENT_AUDIO_SAMPLING_CHANGE:
334         /* This event is received, but not relevant to this test since we're
335          * mostly interested in the audio data, so we ignore it. */
336         break;
337 
338       case CHRE_EVENT_AUDIO_DATA:
339         handleAudioDataEvent(
340             static_cast<const chreAudioDataEvent *>(eventData));
341         break;
342 
343       default:
344         unexpectedEvent(eventType);
345         break;
346     }
347   }
348 
349   mInMethod = false;
350 }
351 
352 }  // namespace general_test
353