• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 #define LOG_TAG "AAudioTest"
18 
19 #include "utils.h"
20 
21 #include <android/binder_ibinder_jni.h>
22 #include <android/binder_status.h>
23 #include <android/log.h>
24 #include <gtest/gtest.h>
25 #include <nativetesthelper_jni/utils.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 #include <any>
31 #include <string>
32 
33 #include "test_aaudio.h"
34 
35 using ::ndk::SpAIBinder;
36 using ::ndk::ScopedAIBinder_DeathRecipient;
37 
getNanoseconds(clockid_t clockId)38 int64_t getNanoseconds(clockid_t clockId) {
39     struct timespec time;
40     int result = clock_gettime(clockId, &time);
41     if (result < 0) {
42         return -errno;
43     }
44     return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
45 }
46 
performanceModeToString(aaudio_performance_mode_t mode)47 const char* performanceModeToString(aaudio_performance_mode_t mode) {
48     switch (mode) {
49         case AAUDIO_PERFORMANCE_MODE_NONE: return "DEFAULT";
50         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: return "POWER_SAVING";
51         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: return "LOW_LATENCY";
52     }
53     return "UNKNOWN";
54 }
55 
sharingModeToString(aaudio_sharing_mode_t mode)56 const char* sharingModeToString(aaudio_sharing_mode_t mode) {
57     switch (mode) {
58         case AAUDIO_SHARING_MODE_SHARED: return "SHARED";
59         case AAUDIO_SHARING_MODE_EXCLUSIVE: return "EXCLUSIVE";
60     }
61     return "UNKNOWN";
62 }
63 
64 // Runs "pm list features" and attempts to find the specified feature in its output.
deviceSupportsFeature(const char * feature)65 bool deviceSupportsFeature(const char* feature) {
66     bool hasFeature = false;
67     FILE *p = popen("/system/bin/pm list features", "re");
68     if (p) {
69       char* line = NULL;
70       size_t len = 0;
71       while (getline(&line, &len, p) > 0) {
72           if (strstr(line, feature)) {
73               hasFeature = true;
74               break;
75           }
76       }
77       pclose(p);
78     } else {
79         __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "popen failed: %d", errno);
80         _exit(EXIT_FAILURE);
81     }
82     __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Feature %s: %ssupported",
83             feature, hasFeature ? "" : "not ");
84     return hasFeature;
85 }
86 
87 // These periods are quite generous. They are not designed to put
88 // any restrictions on the implementation, but only to ensure sanity.
89 // Use int64_t because 96000 * 30000 is close to int32_t limits.
90 const std::map<aaudio_performance_mode_t, int64_t> StreamBuilderHelper::sMaxFramesPerBurstMs =
91 { { AAUDIO_PERFORMANCE_MODE_NONE, 128 },
92   { AAUDIO_PERFORMANCE_MODE_POWER_SAVING, 30 * 1000 },
93   { AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, 40 } };
94 
95 const std::unordered_set<aaudio_format_t> StreamBuilderHelper::sValidStreamFormats =
96         {AAUDIO_FORMAT_PCM_I16, AAUDIO_FORMAT_PCM_FLOAT, AAUDIO_FORMAT_PCM_I24_PACKED,
97          AAUDIO_FORMAT_PCM_I32, AAUDIO_FORMAT_IEC61937};
98 
StreamBuilderHelper(aaudio_direction_t direction,int32_t sampleRate,int32_t channelCount,aaudio_format_t dataFormat,aaudio_sharing_mode_t sharingMode,aaudio_performance_mode_t perfMode)99 StreamBuilderHelper::StreamBuilderHelper(
100         aaudio_direction_t direction, int32_t sampleRate,
101         int32_t channelCount, aaudio_format_t dataFormat,
102         aaudio_sharing_mode_t sharingMode, aaudio_performance_mode_t perfMode)
103         : mDirection{direction},
104           mRequested{sampleRate, channelCount, dataFormat, sharingMode, perfMode},
105           mActual{0, 0, AAUDIO_FORMAT_INVALID, -1, -1}, mFramesPerBurst{-1},
106           mBuilder{nullptr}, mStream{nullptr} {}
107 
~StreamBuilderHelper()108 StreamBuilderHelper::~StreamBuilderHelper() {
109     close();
110 }
111 
initBuilder()112 void StreamBuilderHelper::initBuilder() {
113     ASSERT_EQ(1U, sMaxFramesPerBurstMs.count(mRequested.perfMode));
114 
115     // Use an AAudioStreamBuilder to define the stream.
116     aaudio_result_t result = AAudio_createStreamBuilder(&mBuilder);
117     ASSERT_EQ(AAUDIO_OK, result);
118     ASSERT_TRUE(mBuilder != nullptr);
119 
120     // Request stream properties.
121     AAudioStreamBuilder_setDeviceId(mBuilder, AAUDIO_UNSPECIFIED);
122     AAudioStreamBuilder_setDirection(mBuilder, mDirection);
123     AAudioStreamBuilder_setSampleRate(mBuilder, mRequested.sampleRate);
124     AAudioStreamBuilder_setChannelCount(mBuilder, mRequested.channelCount);
125     AAudioStreamBuilder_setFormat(mBuilder, mRequested.dataFormat);
126     AAudioStreamBuilder_setSharingMode(mBuilder, mRequested.sharingMode);
127     AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequested.perfMode);
128 }
129 
130 // Needs to be a 'void' function due to ASSERT requirements.
createAndVerifyStream(bool * success)131 void StreamBuilderHelper::createAndVerifyStream(bool *success) {
132     *success = false;
133 
134     aaudio_result_t result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
135     if (mRequested.sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE && result != AAUDIO_OK) {
136         __android_log_write(ANDROID_LOG_WARN, LOG_TAG, "Could not open a stream in EXCLUSIVE mode");
137         return;
138     }
139     ASSERT_EQ(AAUDIO_OK, result);
140     ASSERT_TRUE(mStream != nullptr);
141     ASSERT_EQ(AAUDIO_STREAM_STATE_OPEN, AAudioStream_getState(mStream));
142     ASSERT_EQ(mDirection, AAudioStream_getDirection(mStream));
143 
144     mActual.sharingMode = AAudioStream_getSharingMode(mStream);
145     if (mActual.sharingMode != mRequested.sharingMode) {
146         // Since we are covering all possible values, the "actual" mode
147         // will also be tested, so no need to run the same test twice.
148         __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "Sharing mode %s is not available",
149                 sharingModeToString(mRequested.sharingMode));
150         return;
151     }
152 
153     // Check to see what kind of stream we actually got.
154     mActual.sampleRate = AAudioStream_getSampleRate(mStream);
155     ASSERT_GE(mActual.sampleRate, kMinValidSampleRate);
156     ASSERT_LE(mActual.sampleRate, kMaxValidSampleRate);
157 
158     ASSERT_GE(AAudioStream_getHardwareSampleRate(mStream), kMinValidSampleRate);
159     ASSERT_LE(AAudioStream_getHardwareSampleRate(mStream), kMaxValidSampleRate);
160 
161     mActual.channelCount = AAudioStream_getChannelCount(mStream);
162     ASSERT_GE(mActual.channelCount, kMinValidChannelCount);
163     ASSERT_LE(mActual.channelCount, kMaxValidChannelCount);
164 
165     ASSERT_GE(AAudioStream_getHardwareChannelCount(mStream), kMinValidChannelCount);
166     ASSERT_LE(AAudioStream_getHardwareChannelCount(mStream), kMaxValidChannelCount);
167 
168     mActual.dataFormat = AAudioStream_getFormat(mStream);
169     if (mRequested.dataFormat != AAUDIO_FORMAT_UNSPECIFIED) {
170         ASSERT_EQ(mRequested.dataFormat, mActual.dataFormat);
171     }
172 
173     ASSERT_NE(AAudioStream_getHardwareFormat(mStream), AAUDIO_FORMAT_UNSPECIFIED);
174     ASSERT_NE(AAudioStream_getHardwareFormat(mStream), AAUDIO_FORMAT_INVALID);
175     ASSERT_TRUE(sValidStreamFormats.find(AAudioStream_getHardwareFormat(mStream)) !=
176             sValidStreamFormats.end());
177 
178     mActual.perfMode = AAudioStream_getPerformanceMode(mStream);
179     if (mRequested.perfMode != AAUDIO_PERFORMANCE_MODE_NONE
180             && mRequested.perfMode != mActual.perfMode) {
181         // Since we are covering all possible values, the "actual" mode
182         // will also be tested, so no need to run the same test twice.
183         __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "Performance mode %s is not available",
184                 performanceModeToString(mRequested.sharingMode));
185         return;
186     }
187 
188     mFramesPerBurst = AAudioStream_getFramesPerBurst(mStream);
189     ASSERT_GE(mFramesPerBurst, 16);
190     const int32_t maxFramesPerBurst =
191             mActual.sampleRate * sMaxFramesPerBurstMs.at(mActual.perfMode) / MILLIS_PER_SECOND;
192     ASSERT_LE(mFramesPerBurst, maxFramesPerBurst);
193 
194     int32_t actualBufferSize = AAudioStream_getBufferSizeInFrames(mStream);
195     ASSERT_GT(actualBufferSize, 0);
196     ASSERT_GT(AAudioStream_setBufferSizeInFrames(mStream, actualBufferSize), 0);
197 
198     *success = true;
199 }
200 
close()201 void StreamBuilderHelper::close() {
202     if (mBuilder != nullptr) {
203         ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(mBuilder));
204     }
205     if (mStream != nullptr) {
206         ASSERT_EQ(AAUDIO_OK, AAudioStream_close(mStream));
207     }
208 }
209 
streamCommand(StreamCommand cmd,aaudio_stream_state_t fromState,aaudio_stream_state_t toState)210 void StreamBuilderHelper::streamCommand(
211         StreamCommand cmd, aaudio_stream_state_t fromState, aaudio_stream_state_t toState) {
212     ASSERT_EQ(AAUDIO_OK, cmd(mStream));
213     aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
214     ASSERT_EQ(AAUDIO_OK,
215             AAudioStream_waitForStateChange(mStream, fromState, &state, DEFAULT_STATE_TIMEOUT));
216     ASSERT_EQ(toState, state);
217 }
218 
InputStreamBuilderHelper(aaudio_sharing_mode_t requestedSharingMode,aaudio_performance_mode_t requestedPerfMode,aaudio_format_t requestedFormat,int32_t requestedSampleRate)219 InputStreamBuilderHelper::InputStreamBuilderHelper(
220         aaudio_sharing_mode_t requestedSharingMode,
221         aaudio_performance_mode_t requestedPerfMode,
222         aaudio_format_t requestedFormat,
223         int32_t requestedSampleRate)
224         : StreamBuilderHelper{AAUDIO_DIRECTION_INPUT,
225             requestedSampleRate, 1, requestedFormat, requestedSharingMode, requestedPerfMode} {}
226 
227 
OutputStreamBuilderHelper(aaudio_sharing_mode_t requestedSharingMode,aaudio_performance_mode_t requestedPerfMode,aaudio_format_t requestedFormat,int32_t requestedSampleRate)228 OutputStreamBuilderHelper::OutputStreamBuilderHelper(
229         aaudio_sharing_mode_t requestedSharingMode,
230         aaudio_performance_mode_t requestedPerfMode,
231         aaudio_format_t requestedFormat,
232         int32_t requestedSampleRate)
233         : StreamBuilderHelper{AAUDIO_DIRECTION_OUTPUT,
234             requestedSampleRate, 2, requestedFormat, requestedSharingMode, requestedPerfMode} {}
235 
initBuilder()236 void OutputStreamBuilderHelper::initBuilder() {
237     StreamBuilderHelper::initBuilder();
238     AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, kBufferCapacityFrames);
239 }
240 
AAudioExtensions()241 AAudioExtensions::AAudioExtensions() {
242     mMMapSupported =
243             std::any_of(ALL_VALID_OUTPUT_DEVICES.begin(), ALL_VALID_OUTPUT_DEVICES.end(),
244                         [this](AAudio_DeviceType deviceType) {
245                             return isPolicyEnabled(
246                                     getPlatformMMapPolicy(deviceType, AAUDIO_DIRECTION_OUTPUT));
247                         }) ||
248             std::any_of(ALL_VALID_INPUT_DEVICES.begin(), ALL_VALID_INPUT_DEVICES.end(),
249                         [this](AAudio_DeviceType deviceType) {
250                             return isPolicyEnabled(
251                                     getPlatformMMapPolicy(deviceType, AAUDIO_DIRECTION_INPUT));
252                         });
253 
254     mMMapExclusiveSupported =
255             std::any_of(ALL_VALID_OUTPUT_DEVICES.begin(), ALL_VALID_OUTPUT_DEVICES.end(),
256                         [this](AAudio_DeviceType deviceType) {
257                             return isPolicyEnabled(
258                                     getPlatformMMapExclusivePolicy(deviceType,
259                                                                    AAUDIO_DIRECTION_OUTPUT));
260                         }) ||
261             std::any_of(ALL_VALID_INPUT_DEVICES.begin(), ALL_VALID_INPUT_DEVICES.end(),
262                         [this](AAudio_DeviceType deviceType) {
263                             return isPolicyEnabled(
264                                     getPlatformMMapExclusivePolicy(deviceType,
265                                                                    AAUDIO_DIRECTION_INPUT));
266                         });
267 }
268 
getIntegerProperty(const char * name,int defaultValue)269 int AAudioExtensions::getIntegerProperty(const char *name, int defaultValue) {
270     int result = defaultValue;
271     char valueText[PROP_VALUE_MAX] = {0};
272     if (__system_property_get(name, valueText) != 0) {
273         result = atoi(valueText);
274     }
275     return result;
276 }
277 
278 static std::atomic_int sAudioServerCrashCount = 0;
279 static int sLastAudioServerCrashCount = 0;
280 
onBinderDied(void *)281 void onBinderDied(void* /*cookie*/) {
282     sAudioServerCrashCount += 1;
283     AudioServerCrashMonitor::getInstance().onAudioServerCrash();
284 }
285 
AudioServerCrashMonitor()286 AudioServerCrashMonitor::AudioServerCrashMonitor()
287         : mDeathRecipient{ScopedAIBinder_DeathRecipient(
288                 AIBinder_DeathRecipient_new(onBinderDied))} {
289     linkToDeath();
290 }
291 
isDeathRecipientLinked()292 bool AudioServerCrashMonitor::isDeathRecipientLinked() {
293     std::lock_guard<std::mutex> guard(mMutex);
294     return mDeathRecipientLinked;
295 }
296 
linkToDeath()297 void AudioServerCrashMonitor::linkToDeath() {
298     std::lock_guard<std::mutex> guard(mMutex);
299     if (getAudioFlinger_l().get() == nullptr) {
300         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to get audio flinger");
301     } else {
302         auto ret = AIBinder_linkToDeath(mAudioFlinger.get(), mDeathRecipient.get(),
303                                         nullptr /* cookie */);
304         if (ret != STATUS_OK) {
305             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to link to death, err=%d", ret);
306         } else {
307             mDeathRecipientLinked = true;
308         }
309     }
310 }
311 
onAudioServerCrash()312 void AudioServerCrashMonitor::onAudioServerCrash() {
313     std::lock_guard<std::mutex> guard(mMutex);
314     mDeathRecipientLinked = false;
315     mAudioFlinger.set(nullptr);
316 }
317 
318 namespace {
319 
getJNIEnv()320 JNIEnv* getJNIEnv() {
321     JavaVM* vm = GetJavaVM();
322     EXPECT_NE(nullptr, vm);
323     JNIEnv* env = nullptr;
324     jint attach = vm->AttachCurrentThread(&env, nullptr);
325     EXPECT_EQ(JNI_OK, attach);
326     EXPECT_NE(nullptr, env);
327     return env;
328 }
329 
330 #define CALL_JAVA_STATIC_METHOD(_jtype, _jname)                                                 \
331     _jtype callJavaStatic##_jname##Function(JNIEnv* env, const char* className,                 \
332                                             const char* funcName, const char* signature, ...) { \
333         _jtype result;                                                                          \
334         if (env == nullptr) {                                                                   \
335             env = getJNIEnv();                                                                  \
336         }                                                                                       \
337         jclass cl = env->FindClass(className);                                                  \
338         EXPECT_NE(nullptr, cl);                                                                 \
339         jmethodID mid = env->GetStaticMethodID(cl, funcName, signature);                        \
340         EXPECT_NE(nullptr, mid);                                                                \
341         va_list args;                                                                           \
342         va_start(args, signature);                                                              \
343         result = env->CallStatic##_jname##MethodV(cl, mid, args);                               \
344         va_end(args);                                                                           \
345         return result;                                                                          \
346     }
347 
CALL_JAVA_STATIC_METHOD(jobject,Object)348 CALL_JAVA_STATIC_METHOD(jobject, Object)
349 CALL_JAVA_STATIC_METHOD(jboolean, Boolean)
350 CALL_JAVA_STATIC_METHOD(jint, Int)
351 
352 void callJavaStaticVoidFunction(
353         JNIEnv* env, const char* className,
354         const char* funcName, const char* signature, ...) {
355     if (env == nullptr) {
356         env = getJNIEnv();
357     }
358     jclass cl = env->FindClass(className);
359     EXPECT_NE(nullptr, cl);
360     jmethodID mid = env->GetStaticMethodID(cl, funcName, signature);
361     EXPECT_NE(nullptr, mid);
362     va_list args;
363     va_start(args, signature);
364     env->CallStaticVoidMethod(cl, mid, args);
365     va_end(args);
366 }
367 
368 } // namespace
369 
getAudioFlinger_l()370 SpAIBinder AudioServerCrashMonitor::getAudioFlinger_l() {
371     if (mAudioFlinger.get() != nullptr) {
372         return mAudioFlinger;
373     }
374 
375     JNIEnv *env = getJNIEnv();
376     jobject object = callJavaStaticObjectFunction(
377             env, "android/nativemedia/aaudio/AAudioTests",
378             "getAudioFlinger", "()Landroid/os/IBinder;");
379     EXPECT_NE(nullptr, object);
380 
381     mAudioFlinger = SpAIBinder(AIBinder_fromJavaBinder(env, object));
382     return mAudioFlinger;
383 }
384 
SetUp()385 void AAudioCtsBase::SetUp() {
386     checkIfAudioServerCrash();
387 }
388 
TearDown()389 void AAudioCtsBase::TearDown() {
390     checkIfAudioServerCrash();
391 }
392 
checkIfAudioServerCrash()393 void AAudioCtsBase::checkIfAudioServerCrash() {
394     EXPECT_EQ(sLastAudioServerCrashCount, sAudioServerCrashCount);
395     sLastAudioServerCrashCount = sAudioServerCrashCount;
396     EXPECT_TRUE(AudioServerCrashMonitor::getInstance().isDeathRecipientLinked());
397     if (!AudioServerCrashMonitor::getInstance().isDeathRecipientLinked()) {
398         AudioServerCrashMonitor::getInstance().linkToDeath();
399     }
400 }
401 
isIEC61937Supported()402 bool isIEC61937Supported() {
403     return (bool) callJavaStaticBooleanFunction(
404             nullptr, "android/nativemedia/aaudio/AAudioTests", "isIEC61937Supported", "()Z");
405 }
406 
isEchoReferenceSupported()407 bool isEchoReferenceSupported() {
408     return (bool) callJavaStaticBooleanFunction(
409             nullptr, "android/nativemedia/aaudio/AAudioTests", "isEchoReferenceSupported", "()Z");
410 }
411 
enableAudioOutputPermission()412 void enableAudioOutputPermission() {
413     callJavaStaticVoidFunction(
414             nullptr, "android/nativemedia/aaudio/AAudioTests", "enableAudioOutputPermission",
415             "()V");
416 }
417 
enableAudioHotwordPermission()418 void enableAudioHotwordPermission() {
419     callJavaStaticVoidFunction(
420             nullptr, "android/nativemedia/aaudio/AAudioTests", "enableAudioHotwordPermission",
421             "()V");
422 }
423 
disablePermissions()424 void disablePermissions() {
425     callJavaStaticVoidFunction(
426             nullptr, "android/nativemedia/aaudio/AAudioTests", "disablePermissions", "()V");
427 }
428 
isCompressedFormat(aaudio_format_t format)429 bool isCompressedFormat(aaudio_format_t format) {
430     switch (format) {
431         case AAUDIO_FORMAT_PCM_I16:
432         case AAUDIO_FORMAT_PCM_FLOAT:
433         case AAUDIO_FORMAT_PCM_I24_PACKED:
434         case AAUDIO_FORMAT_PCM_I32:
435             return false;
436         default:
437             return true;
438     }
439 }
440 
getDeviceTypeFromId(int32_t deviceId)441 int getDeviceTypeFromId(int32_t deviceId) {
442     return callJavaStaticIntFunction(nullptr, "android/nativemedia/aaudio/AAudioTests",
443                                      "getDeviceTypeFromId", "(I)I", (jint)deviceId);
444 }
445 
getOutChannelCountMax()446 int getOutChannelCountMax() {
447     static int outChannelCountMax =
448             (int)callJavaStaticIntFunction(nullptr, "android/nativemedia/aaudio/AAudioTests",
449                                            "getOutChannelCountMax", "()I");
450     return outChannelCountMax;
451 }
452