1 /*
2 * Copyright (C) 2021 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 <thread>
18
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "AudioTrackTests"
21
22 #include <android-base/logging.h>
23 #include <binder/ProcessState.h>
24 #include <gtest/gtest.h>
25
26 #include "audio_test_utils.h"
27 #include "test_execution_tracer.h"
28
29 using namespace android;
30
31 // Test that the basic constructor returns an object that doesn't crash
32 // on stop() or destruction.
33
TEST(AudioTrackTestBasic,EmptyAudioTrack)34 TEST(AudioTrackTestBasic, EmptyAudioTrack) {
35 AttributionSourceState attributionSource;
36 attributionSource.packageName = "AudioTrackTest";
37 attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
38 attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
39 attributionSource.token = sp<BBinder>::make();
40 const auto at = sp<AudioTrack>::make(attributionSource);
41
42 EXPECT_EQ(NO_INIT, at->initCheck());
43 EXPECT_EQ(true, at->stopped());
44
45 // ensure we do not crash.
46 at->stop();
47 }
48
TEST(AudioTrackTest,TestPlayTrack)49 TEST(AudioTrackTest, TestPlayTrack) {
50 const auto ap = sp<AudioPlayback>::make(44100 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT,
51 AUDIO_CHANNEL_OUT_STEREO, AUDIO_OUTPUT_FLAG_NONE,
52 AUDIO_SESSION_NONE, AudioTrack::TRANSFER_OBTAIN);
53 ASSERT_NE(nullptr, ap);
54 ASSERT_EQ(OK, ap->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
55 << "Unable to open Resource";
56 EXPECT_EQ(OK, ap->create()) << "track creation failed";
57 EXPECT_EQ(OK, ap->start()) << "audio track start failed";
58 EXPECT_EQ(OK, ap->onProcess());
59 ap->stop();
60 }
61
TEST(AudioTrackTest,TestSeek)62 TEST(AudioTrackTest, TestSeek) {
63 const auto ap = sp<AudioPlayback>::make(
64 44100 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO);
65 ASSERT_NE(nullptr, ap);
66 ASSERT_EQ(OK, ap->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
67 << "Unable to open Resource";
68 EXPECT_EQ(OK, ap->create()) << "track creation failed";
69 EXPECT_EQ(OK, ap->start()) << "audio track start failed";
70 EXPECT_EQ(OK, ap->onProcess(true));
71 ap->stop();
72 }
73
TEST(AudioTrackTest,OffloadOrDirectPlayback)74 TEST(AudioTrackTest, OffloadOrDirectPlayback) {
75 audio_offload_info_t info = AUDIO_INFO_INITIALIZER;
76 info.sample_rate = 44100;
77 info.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
78 info.format = AUDIO_FORMAT_MP3;
79 info.stream_type = AUDIO_STREAM_MUSIC;
80 info.bit_rate = 192;
81 info.duration_us = 120 * 1000000; // 120 sec
82
83 audio_config_base_t config = {/* .sample_rate = */ info.sample_rate,
84 /* .channel_mask = */ info.channel_mask,
85 /* .format = */ AUDIO_FORMAT_PCM_16_BIT};
86 audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
87 attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
88 attributes.usage = AUDIO_USAGE_MEDIA;
89 attributes.flags = AUDIO_FLAG_NONE;
90
91 if (!AudioTrack::isDirectOutputSupported(config, attributes) &&
92 AUDIO_OFFLOAD_NOT_SUPPORTED == AudioSystem::getOffloadSupport(info)) {
93 GTEST_SKIP() << "offload or direct playback is not supported";
94 }
95 sp<AudioPlayback> ap = nullptr;
96 if (AUDIO_OFFLOAD_NOT_SUPPORTED != AudioSystem::getOffloadSupport(info)) {
97 ap = sp<AudioPlayback>::make(info.sample_rate, info.format, info.channel_mask,
98 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD, AUDIO_SESSION_NONE,
99 AudioTrack::TRANSFER_OBTAIN, nullptr, &info);
100 } else {
101 ap = sp<AudioPlayback>::make(config.sample_rate, config.format, config.channel_mask,
102 AUDIO_OUTPUT_FLAG_DIRECT, AUDIO_SESSION_NONE,
103 AudioTrack::TRANSFER_OBTAIN);
104 }
105 ASSERT_NE(nullptr, ap);
106 EXPECT_EQ(OK, ap->create()) << "track creation failed";
107 audio_dual_mono_mode_t mode;
108 if (OK != ap->getAudioTrackHandle()->getDualMonoMode(&mode)) {
109 std::cerr << "no dual mono presentation is available" << std::endl;
110 }
111 if (OK != ap->getAudioTrackHandle()->setDualMonoMode(AUDIO_DUAL_MONO_MODE_LR)) {
112 std::cerr << "no dual mono presentation is available" << std::endl;
113 } else {
114 EXPECT_EQ(OK, ap->getAudioTrackHandle()->getDualMonoMode(&mode));
115 EXPECT_EQ(AUDIO_DUAL_MONO_MODE_LR, mode);
116 }
117 float leveldB;
118 if (OK != ap->getAudioTrackHandle()->getAudioDescriptionMixLevel(&leveldB)) {
119 std::cerr << "Audio Description mixing is unavailable" << std::endl;
120 }
121 if (OK != ap->getAudioTrackHandle()->setAudioDescriptionMixLevel(3.14f)) {
122 std::cerr << "Audio Description mixing is unavailable" << std::endl;
123 } else {
124 EXPECT_EQ(OK, ap->getAudioTrackHandle()->getAudioDescriptionMixLevel(&leveldB));
125 EXPECT_EQ(3.14f, leveldB);
126 }
127 AudioPlaybackRate audioRate;
128 audioRate = ap->getAudioTrackHandle()->getPlaybackRate();
129 std::cerr << "playback speed :: " << audioRate.mSpeed << std::endl
130 << "playback pitch :: " << audioRate.mPitch << std::endl;
131 audioRate.mSpeed = 2.0f;
132 audioRate.mPitch = 2.0f;
133 audioRate.mStretchMode = AUDIO_TIMESTRETCH_STRETCH_VOICE;
134 audioRate.mFallbackMode = AUDIO_TIMESTRETCH_FALLBACK_MUTE;
135 EXPECT_TRUE(isAudioPlaybackRateValid(audioRate));
136 if (OK != ap->getAudioTrackHandle()->setPlaybackRate(audioRate)) {
137 std::cerr << "unable to set playback rate parameters" << std::endl;
138 } else {
139 AudioPlaybackRate audioRateLocal;
140 audioRateLocal = ap->getAudioTrackHandle()->getPlaybackRate();
141 EXPECT_TRUE(isAudioPlaybackRateEqual(audioRate, audioRateLocal));
142 }
143 ap->stop();
144 }
145
TEST(AudioTrackTest,TestAudioCbNotifier)146 TEST(AudioTrackTest, TestAudioCbNotifier) {
147 const auto ap = sp<AudioPlayback>::make(0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT,
148 AUDIO_CHANNEL_OUT_STEREO, AUDIO_OUTPUT_FLAG_FAST,
149 AUDIO_SESSION_NONE, AudioTrack::TRANSFER_SHARED);
150 ASSERT_NE(nullptr, ap);
151 ASSERT_EQ(OK, ap->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
152 << "Unable to open Resource";
153 EXPECT_EQ(OK, ap->create()) << "track creation failed";
154 EXPECT_EQ(BAD_VALUE, ap->getAudioTrackHandle()->addAudioDeviceCallback(nullptr));
155 sp<OnAudioDeviceUpdateNotifier> cb = sp<OnAudioDeviceUpdateNotifier>::make();
156 sp<OnAudioDeviceUpdateNotifier> cbOld = sp<OnAudioDeviceUpdateNotifier>::make();
157 EXPECT_EQ(OK, ap->getAudioTrackHandle()->addAudioDeviceCallback(cbOld));
158 EXPECT_EQ(INVALID_OPERATION, ap->getAudioTrackHandle()->addAudioDeviceCallback(cbOld));
159 EXPECT_EQ(OK, ap->getAudioTrackHandle()->addAudioDeviceCallback(cb));
160 EXPECT_EQ(OK, ap->start()) << "audio track start failed";
161 EXPECT_EQ(OK, ap->onProcess());
162 EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
163 const auto [oldAudioIo, oldDeviceIds] = cbOld->getLastPortAndDevices();
164 EXPECT_EQ(AUDIO_IO_HANDLE_NONE, oldAudioIo);
165 EXPECT_TRUE(oldDeviceIds.empty());
166 const auto [audioIo, deviceIds] = cb->getLastPortAndDevices();
167 EXPECT_NE(AUDIO_IO_HANDLE_NONE, audioIo);
168 EXPECT_FALSE(deviceIds.empty());
169 EXPECT_EQ(audioIo, ap->getAudioTrackHandle()->getOutput());
170 DeviceIdVector routedDeviceIds = ap->getAudioTrackHandle()->getRoutedDeviceIds();
171 EXPECT_TRUE(areDeviceIdsEqual(routedDeviceIds, deviceIds));
172 String8 keys;
173 keys = ap->getAudioTrackHandle()->getParameters(keys);
174 if (!keys.empty()) {
175 std::cerr << "track parameters :: " << keys << std::endl;
176 }
177 EXPECT_TRUE(checkPatchPlayback(audioIo, deviceIds));
178 EXPECT_EQ(BAD_VALUE, ap->getAudioTrackHandle()->removeAudioDeviceCallback(nullptr));
179 EXPECT_EQ(INVALID_OPERATION, ap->getAudioTrackHandle()->removeAudioDeviceCallback(cbOld));
180 EXPECT_EQ(OK, ap->getAudioTrackHandle()->removeAudioDeviceCallback(cb));
181 ap->stop();
182 }
183
184 class AudioTrackOffloadTest : public ::testing::Test {
185 protected:
TearDown()186 void TearDown() override {
187 if (!IsSkipped()) {
188 // Let the offload AF stream to exit to avoid interfering with other tests.
189 std::this_thread::sleep_for(std::chrono::milliseconds(750));
190 }
191 }
192 bool halSupportsClipTransition() const;
193 void testPlayback(bool testDrainPause, sp<AudioPlayback>* outPlayback = nullptr);
194 };
195
halSupportsClipTransition() const196 bool AudioTrackOffloadTest::halSupportsClipTransition() const {
197 // TODO: Check for the HAL type (HIDL/AIDL) and version. HIDL and AIDL V4 should also
198 // support this.
199 AudioParameter param;
200 param.addKey(String8(AudioParameter::keyClipTransitionSupport));
201 String8 values = AudioSystem::getParameters(AUDIO_IO_HANDLE_NONE, param.keysToString());
202 LOG(DEBUG) << __func__ << ": values \"" << values << "\"";
203 return !values.empty();
204 }
205
testPlayback(bool testDrainPause,sp<AudioPlayback> * outPlayback)206 void AudioTrackOffloadTest::testPlayback(bool testDrainPause, sp<AudioPlayback>* outPlayback) {
207 audio_offload_info_t info = AUDIO_INFO_INITIALIZER;
208 info.sample_rate = 48000;
209 info.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
210 info.format = AUDIO_FORMAT_APE;
211 info.stream_type = AUDIO_STREAM_MUSIC;
212 info.bit_rate = 236256;
213 info.duration_us = 120 * 1000000; // 120 sec to ensure the offloading choice
214
215 if (AUDIO_OFFLOAD_NOT_SUPPORTED == AudioSystem::getOffloadSupport(info)) {
216 GTEST_SKIP() << "offload playback is not supported for "
217 << audio_format_to_string(info.format);
218 }
219 auto ap = sp<AudioPlayback>::make(info.sample_rate, info.format, info.channel_mask,
220 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD, AUDIO_SESSION_NONE,
221 AudioTrack::TRANSFER_OBTAIN, nullptr, &info);
222 ASSERT_EQ(OK, ap->loadResource("/data/local/tmp/sine960hz_48000_3s.ape"))
223 << "unable to open the media file";
224 ASSERT_EQ(OK, ap->create()) << "track creation failed";
225 ASSERT_EQ(OK, ap->start()) << "audio track start failed";
226 LOG(INFO) << __func__ << ": Started track";
227 EXPECT_EQ(OK, ap->onProcess());
228 LOG(INFO) << __func__ << ": onProcess done";
229 if (!outPlayback) {
230 ap->stop();
231 LOG(INFO) << __func__ << ": Stopped track";
232 }
233 if (testDrainPause) {
234 // Wait for draining to start, no event for this.
235 std::this_thread::sleep_for(std::chrono::milliseconds(200));
236 LOG(INFO) << __func__ << ": Pausing drain";
237 ap->pause();
238 LOG(INFO) << __func__ << ": Resuming drain";
239 ap->resume();
240 }
241 if (!outPlayback) {
242 LOG(INFO) << __func__ << ": Waiting for stream end";
243 EXPECT_TRUE(ap->waitForStreamEnd()) << "Did not receive onStreamEnd";
244 } else {
245 *outPlayback = std::move(ap);
246 }
247 }
248
TEST_F(AudioTrackOffloadTest,Completion)249 TEST_F(AudioTrackOffloadTest, Completion) {
250 testPlayback(false /*testDrainPause*/);
251 }
252
TEST_F(AudioTrackOffloadTest,DrainPause)253 TEST_F(AudioTrackOffloadTest, DrainPause) {
254 if (!halSupportsClipTransition()) {
255 // TODO: In theory, this should also work w/o having the proper clip transition
256 // support, but as a fact it was not. Need to figure out why.
257 GTEST_SKIP() << "Proper indication of clip transition is not supported";
258 }
259 testPlayback(true /*testDrainPause*/);
260 }
261
262 // Similar to AudioTrackOffloadTest.testMultipleAudioTrackOffloadPreemption
TEST_F(AudioTrackOffloadTest,ClipPreemption)263 TEST_F(AudioTrackOffloadTest, ClipPreemption) {
264 if (!halSupportsClipTransition()) {
265 GTEST_SKIP() << "Proper indication of clip transition is not supported";
266 }
267 sp<AudioPlayback> trackOne, trackTwo;
268 {
269 SCOPED_TRACE("track 1");
270 LOG(INFO) << __func__ << ": Creating and starting track 1";
271 ASSERT_NO_FATAL_FAILURE(testPlayback(false /*testDrainPause*/, &trackOne));
272 }
273 {
274 SCOPED_TRACE("track 2");
275 // Wait for track 1 to start playing, no event for this.
276 std::this_thread::sleep_for(std::chrono::milliseconds(300));
277 LOG(INFO) << __func__ << ": Creating and starting track 2";
278 ASSERT_NO_FATAL_FAILURE(testPlayback(false /*testDrainPause*/, &trackTwo));
279 std::this_thread::sleep_for(std::chrono::milliseconds(200));
280 trackTwo->stop();
281 }
282 LOG(INFO) << __func__ << ": Waiting for stream end on track 2";
283 EXPECT_TRUE(trackTwo->waitForStreamEnd()) << "Did not receive onStreamEnd on track 2";
284 }
285
286 class AudioTrackCreateTest
287 : public ::testing::TestWithParam<std::tuple<uint32_t, audio_format_t, audio_channel_mask_t,
288 audio_output_flags_t, audio_session_t>> {
289 public:
AudioTrackCreateTest()290 AudioTrackCreateTest()
291 : mSampleRate(std::get<0>(GetParam())),
292 mFormat(std::get<1>(GetParam())),
293 mChannelMask(std::get<2>(GetParam())),
294 mFlags(std::get<3>(GetParam())),
295 mSessionId(std::get<4>(GetParam())){};
296
297 const uint32_t mSampleRate;
298 const audio_format_t mFormat;
299 const audio_channel_mask_t mChannelMask;
300 const audio_output_flags_t mFlags;
301 const audio_session_t mSessionId;
302
303 sp<AudioPlayback> mAP;
304
SetUp()305 virtual void SetUp() override {
306 mAP = sp<AudioPlayback>::make(mSampleRate, mFormat, mChannelMask, mFlags,
307 mSessionId);
308 ASSERT_NE(nullptr, mAP);
309 ASSERT_EQ(OK, mAP->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
310 << "Unable to open Resource";
311 ASSERT_EQ(OK, mAP->create()) << "track creation failed";
312 }
313
TearDown()314 virtual void TearDown() override {
315 if (mAP) mAP->stop();
316 }
317 };
318
TEST_P(AudioTrackCreateTest,TestCreateTrack)319 TEST_P(AudioTrackCreateTest, TestCreateTrack) {
320 EXPECT_EQ(mFormat, mAP->getAudioTrackHandle()->format());
321 EXPECT_EQ(audio_channel_count_from_out_mask(mChannelMask),
322 mAP->getAudioTrackHandle()->channelCount());
323 if (mSampleRate != 0) EXPECT_EQ(mSampleRate, mAP->getAudioTrackHandle()->getSampleRate());
324 if (mSessionId != AUDIO_SESSION_NONE)
325 EXPECT_EQ(mSessionId, mAP->getAudioTrackHandle()->getSessionId());
326 EXPECT_EQ(mSampleRate, mAP->getAudioTrackHandle()->getOriginalSampleRate());
327 EXPECT_EQ(OK, mAP->start()) << "audio track start failed";
328 EXPECT_EQ(OK, mAP->onProcess());
329 }
330
331 // sampleRate, format, channelMask, flags, sessionId
332 INSTANTIATE_TEST_SUITE_P(
333 AudioTrackParameterizedTest, AudioTrackCreateTest,
334 ::testing::Combine(::testing::Values(48000), ::testing::Values(AUDIO_FORMAT_PCM_16_BIT),
335 ::testing::Values(AUDIO_CHANNEL_OUT_STEREO),
336 ::testing::Values(AUDIO_OUTPUT_FLAG_NONE,
337 AUDIO_OUTPUT_FLAG_PRIMARY | AUDIO_OUTPUT_FLAG_FAST,
338 AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_FAST,
339 AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
340 ::testing::Values(AUDIO_SESSION_NONE)));
341
main(int argc,char ** argv)342 int main(int argc, char** argv) {
343 android::ProcessState::self()->startThreadPool();
344 ::testing::InitGoogleTest(&argc, argv);
345 ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
346 return RUN_ALL_TESTS();
347 }
348