• 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 
17 #include <general_test/basic_audio_test.h>
18 
19 #include <shared/send_message.h>
20 
21 using nanoapp_testing::sendFatalFailureToHost;
22 using nanoapp_testing::sendSuccessToHost;
23 
24 namespace general_test {
25 namespace {
26 
27 //! Unit conversion nanoseconds per second.
28 constexpr uint64_t kNanosecondsPerSecond = 1000000000;
29 
30 //! This is a reasonably high limit on the number of audio sources that a system
31 //! would expose. Use this to verify that there are no gaps in the source
32 //! handles.
33 constexpr uint32_t kMaxAudioSources = 128;
34 
35 //! This is a reasonably high limit on the sample rate for a source that the
36 //! system would expose. Sampling rates above 96kHz are likely to be too high
37 //! for always-on low-power use-cases. Yes, this omits 192kHz, but that is
38 //! generally reserved for professional audio/recording and mixing applications.
39 //! Even 96kHz is a stretch, but capping it here allows room to grow. Expected
40 //! values are more like 16kHz.
41 constexpr uint32_t kMaxAudioSampleRate = 96000;
42 
43 //! Provide a floor for the sampling rate of an audio source that the system
44 //! would expose. Nyquist theorem dictates that the maximum frequency that can
45 //! be reproduced from given sequence of samples is equal to half that of the
46 //! sampling rate. This sets a lower bound to try to detect bugs or glitches.
47 constexpr uint32_t kMinAudioSampleRate = 4000;
48 
49 //! Provide a floor for buffer duration. This ensures that at the maximum
50 //! sample rate possible, a minimum number of samples will be delivered in
51 //! a batch.
52 constexpr uint64_t kMinBufferDuration =
53     (kNanosecondsPerSecond / kMaxAudioSampleRate) * 10;
54 
55 //! Provide a ceiling for the maximum buffer duration. This is to catch buggy
56 //! descriptors of audio sources who expose very long buffers of data which are
57 //! not practical for always-on, low-power use-cases.
58 constexpr uint64_t kMaxBufferDuration = kNanosecondsPerSecond * 120;
59 
60 /**
61  * @return true if the character is ASCII printable.
62  */
isAsciiPrintable(char c)63 bool isAsciiPrintable(char c) {
64   // A simple enough test to verify that a character is printable. These
65   // constants can be verified by reviewing an ASCII chart. All printable
66   // characters that we care about for CHRE lie between these two bounds and are
67   // contiguous.
68   return (c >= ' ' && c <= '~');
69 }
70 
71 /**
72  * @return true if the supplied string is printable, null-terminated and not
73  * longer than the supplied length (including null-terminator).
74  */
verifyStringWithLength(const char * str,size_t length)75 bool verifyStringWithLength(const char *str, size_t length) {
76   bool nullTerminatorFound = false;
77   bool isPrintable = true;
78   for (size_t i = 0; i < length; i++) {
79     if (str[i] == '\0') {
80       nullTerminatorFound = true;
81       break;
82     } else if (!isAsciiPrintable(str[i])) {
83       isPrintable = false;
84       break;
85     }
86   }
87 
88   return (isPrintable && nullTerminatorFound);
89 }
90 
91 /**
92  * Validates the fields of a chreAudioSource provided by the framework and posts
93  * a failure if the source descriptor is malformed.
94  *
95  * @return true if the source was valid.
96  */
validateAudioSource(uint32_t handle,const struct chreAudioSource & source)97 bool validateAudioSource(uint32_t handle,
98                          const struct chreAudioSource& source) {
99   bool valid = false;
100   if (!verifyStringWithLength(source.name, CHRE_AUDIO_SOURCE_NAME_MAX_SIZE)) {
101     sendFatalFailureToHost(
102         "Invalid audio source name for handle ", &handle);
103   } else if (source.sampleRate > kMaxAudioSampleRate
104       || source.sampleRate < kMinAudioSampleRate) {
105     sendFatalFailureToHost(
106         "Invalid audio sample rate for handle ", &handle);
107   } else if (source.minBufferDuration < kMinBufferDuration
108       || source.minBufferDuration > kMaxBufferDuration) {
109     sendFatalFailureToHost(
110         "Invalid min buffer duration for handle ", &handle);
111   } else if (source.maxBufferDuration < kMinBufferDuration
112       || source.maxBufferDuration > kMaxBufferDuration) {
113     sendFatalFailureToHost(
114         "Invalid max buffer duration for handle ", &handle);
115   } else if (source.format != CHRE_AUDIO_DATA_FORMAT_8_BIT_U_LAW
116       && source.format != CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM) {
117     sendFatalFailureToHost(
118         "Invalid audio format for handle ", &handle);
119   } else {
120     valid = true;
121   }
122 
123   return valid;
124 }
125 
validateMinimumAudioSource(const struct chreAudioSource & source)126 bool validateMinimumAudioSource(const struct chreAudioSource& source) {
127   // CHQTS requires a 16kHz, PCM-format, 2 second buffer.
128   constexpr uint32_t kRequiredSampleRate = 16000;
129   constexpr uint64_t kRequiredBufferDuration = 2 * kNanosecondsPerSecond;
130 
131   // Ensure that the minimum buffer size is less than or equal to the required
132   // size.
133   return (source.sampleRate == kRequiredSampleRate
134       && source.minBufferDuration <= kRequiredBufferDuration
135       && source.maxBufferDuration >= kRequiredBufferDuration
136       && source.format == CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM);
137 }
138 
139 /**
140  * Attempts to query for all audio sources up to kMaxAudioSources and posts a
141  * failure if a gap is found in the handles or the provided descriptor is
142  * invalid.
143  */
validateAudioSources()144 void validateAudioSources() {
145   uint32_t validHandleCount = 0;
146   bool previousSourceFound = true;
147   bool minimumRequirementMet = false;
148   for (uint32_t handle = 0; handle < kMaxAudioSources; handle++) {
149     struct chreAudioSource audioSource;
150     bool sourceFound = chreAudioGetSource(handle, &audioSource);
151     if (sourceFound) {
152       validHandleCount++;
153       if (!previousSourceFound) {
154         sendFatalFailureToHost(
155             "Gap detected in audio handles at ", &handle);
156       } else {
157         bool valid = validateAudioSource(handle, audioSource);
158         if (valid && !minimumRequirementMet) {
159           minimumRequirementMet = validateMinimumAudioSource(audioSource);
160         }
161       }
162     }
163 
164     previousSourceFound = sourceFound;
165   }
166 
167   if (validHandleCount > 0) {
168     if (!minimumRequirementMet) {
169       sendFatalFailureToHost(
170           "Failed to meet minimum audio source requirements");
171     }
172 
173     if (validHandleCount == kMaxAudioSources) {
174       sendFatalFailureToHost(
175           "System is reporting too many audio sources");
176     }
177   }
178 }
179 
180 }  // anonymous namespace
181 
BasicAudioTest()182 BasicAudioTest::BasicAudioTest()
183     : Test(CHRE_API_VERSION_1_2),
184       mInMethod(false),
185       mState(State::kPreStart) {}
186 
setUp(uint32_t messageSize,const void *)187 void BasicAudioTest::setUp(uint32_t messageSize,
188                            const void * /* message */) {
189   if (messageSize != 0) {
190     sendFatalFailureToHost(
191         "Beginning message expects 0 additional bytes, got ",
192         &messageSize);
193   }
194 
195   validateAudioSources();
196   sendSuccessToHost();
197 }
198 
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)199 void BasicAudioTest::handleEvent(
200     uint32_t senderInstanceId, uint16_t eventType, const void* eventData) {
201   if (mInMethod) {
202     sendFatalFailureToHost("handleEvent() invoked while already in method.");
203   }
204 
205   mInMethod = true;
206 
207   if (mState == State::kPreStart) {
208     unexpectedEvent(eventType);
209   } else {
210     // TODO: Handle audio data from sources, perform basic sanity checks on it.
211   }
212 
213   mInMethod = false;
214 }
215 
216 }  // namespace general_test
217