/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Test whether a stream dies if it is written to after a delay. // Maybe because the message queue from the AAudio service fills up. #define LOG_TAG "test_full_queue" //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include constexpr int64_t kNanosPerMillisecond = 1e6; constexpr int64_t kMicrosPerMillisecond = 1000; constexpr int64_t kTimeoutNanos = 50 * kNanosPerMillisecond; constexpr int kNumFrames = 256; constexpr int kChannelCount = 2; constexpr int kNumSamples = kChannelCount * kNumFrames; static void checkFullQueue(aaudio_performance_mode_t perfMode, aaudio_sharing_mode_t sharingMode, int32_t sleepMillis) { aaudio_result_t result; std::unique_ptr buffer = std::make_unique(kNumSamples); for (int i = 0; i < kNumSamples; i++) { buffer[i] = (drand48() - 0.5) * 0.05; // random buzzy waveform } AAudioStreamBuilder *aaudioBuilder = nullptr; // Use an AAudioStreamBuilder to contain requested parameters. ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder)); // Request stream properties. AAudioStreamBuilder_setChannelCount(aaudioBuilder, kChannelCount); AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode); AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode); // Create an AAudioStream using the Builder. AAudioStream *aaudioStream = nullptr; ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream)); AAudioStreamBuilder_delete(aaudioBuilder); int bufferSize = std::max( 2 * AAudioStream_getFramesPerBurst(aaudioStream), 2 * kNumFrames ); AAudioStream_setBufferSizeInFrames(aaudioStream, bufferSize); EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream)); #if 0 int32_t capacity = AAudioStream_getBufferCapacityInFrames(aaudioStream); ASSERT_LT(20, capacity); int numWrites = 30 * capacity / kNumFrames; #else int32_t sampleRate = AAudioStream_getSampleRate(aaudioStream); EXPECT_LT(7000, sampleRate); int numWrites = 1 * sampleRate / kNumFrames; #endif for (int i = 0; i < numWrites/2; i++) { result = AAudioStream_write(aaudioStream, buffer.get(), kNumFrames, kTimeoutNanos); EXPECT_EQ(kNumFrames, result); if (kNumFrames != result) break; } // Sleep for awhile. This might kill the stream. ALOGD("%s() start sleeping %d millis", __func__, sleepMillis); usleep(sleepMillis * kMicrosPerMillisecond); ALOGD("%s() start writing", __func__); // Let CPU catch up with the hardware. int64_t framesRead = AAudioStream_getFramesRead(aaudioStream); int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream); ALOGD("%s() after hang, read = %jd, written = %jd, w-r = %jd", __func__, (intmax_t) framesRead, (intmax_t) framesWritten, (intmax_t)(framesWritten - framesRead)); int countDown = 2 * sleepMillis * sampleRate / (kNumFrames * 1000); do { result = AAudioStream_write(aaudioStream, buffer.get(), kNumFrames, kTimeoutNanos); ALOGD("%s() catching up, wrote %d frames", __func__, result); framesRead = AAudioStream_getFramesRead(aaudioStream); framesWritten = AAudioStream_getFramesWritten(aaudioStream); countDown--; } while ((framesRead > framesWritten) && (countDown > 0) && (kNumFrames == result)); EXPECT_LE(framesRead, framesWritten); EXPECT_GT(countDown, 0); EXPECT_EQ(kNumFrames, result); ALOGD("%s() after catch up, read = %jd, written = %jd, w-r = %jd", __func__, (intmax_t) framesRead, (intmax_t) framesWritten, (intmax_t)(framesWritten - framesRead)); // Try to keep the stream full. for (int i = 0; i < numWrites; i++) { ALOGD("%s() try to write", __func__); result = AAudioStream_write(aaudioStream, buffer.get(), kNumFrames, kTimeoutNanos); ALOGD("%s() wrote %d frames", __func__, result); EXPECT_EQ(kNumFrames, result); if (kNumFrames != result) break; } EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream)); EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream)); } // ==== Default Latency, SHARED =========== TEST(test_full_queue, aaudio_full_queue_perf_none_sh_50) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_SHARING_MODE_SHARED, 50 /* sleepMillis */); } TEST(test_full_queue, aaudio_full_queue_perf_none_sh_400) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_SHARING_MODE_SHARED, 400 /* sleepMillis */); } TEST(test_full_queue, aaudio_full_queue_perf_none_sh_1000) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_SHARING_MODE_SHARED, 1000 /* sleepMillis */); } // ==== Low Latency, SHARED =========== TEST(test_full_queue, aaudio_full_queue_low_latency_sh_50) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_SHARING_MODE_SHARED, 50 /* sleepMillis */); } TEST(test_full_queue, aaudio_full_queue_low_latency_sh_400) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_SHARING_MODE_SHARED, 400 /* sleepMillis */); } TEST(test_full_queue, aaudio_full_queue_low_latency_sh_1000) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_SHARING_MODE_SHARED, 1000 /* sleepMillis */); } // ==== Low Latency, EXCLUSIVE =========== TEST(test_full_queue, aaudio_full_queue_low_latency_excl_50) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_SHARING_MODE_EXCLUSIVE, 50 /* sleepMillis */); } TEST(test_full_queue, aaudio_full_queue_low_latency_excl_400) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_SHARING_MODE_EXCLUSIVE, 400 /* sleepMillis */); } TEST(test_full_queue, aaudio_full_queue_low_latency_excl_1000) { checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_SHARING_MODE_EXCLUSIVE, 1000 /* sleepMillis */); }