• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2022 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 package android.media.audio.cts
18 
19 import android.content.pm.PackageManager
20 import android.media.AudioAttributes
21 import android.media.AudioFormat
22 import android.media.AudioManager
23 import android.media.AudioProfile
24 import android.media.AudioTrack
25 import androidx.test.ext.junit.runners.AndroidJUnit4
26 import androidx.test.platform.app.InstrumentationRegistry
27 import com.android.compatibility.common.util.NonMainlineTest
28 import org.junit.Assert.fail
29 import org.junit.Assume.assumeTrue
30 import org.junit.Before
31 import org.junit.Test
32 import org.junit.runner.RunWith
33 
34 @NonMainlineTest
35 @RunWith(AndroidJUnit4::class)
36 class DirectAudioProfilesForAttributesTest {
37 
38     private lateinit var audioManager: AudioManager
39 
40     @Before
41     fun setup() {
42         val context = InstrumentationRegistry.getInstrumentation().context
43         assumeTrue(
44             context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)
45         )
46 
47         audioManager = context.getSystemService(AudioManager::class.java)
48     }
49 
50     /**
51      * Test that only AudioProfiles returned in getDirectProfilesForAttributes can create direct
52      * AudioTracks
53      */
54     @Test
55     fun testCreateDirectAudioTracksOnlyForGetDirectProfilesForAttributes() {
56         for (usage in AudioAttributes.getSdkUsages()) {
57             val audioAttributes = AudioAttributes.Builder()
58                 .setUsage(usage)
59                 .build()
60             val directProfiles = audioManager.getDirectProfilesForAttributes(audioAttributes)
61 
62             // All compressed format (non pcm) profiles can create direct AudioTracks.
63             // getDirectProfilesForAttributes does not include profiles supporting
64             // compressed playback in offload mode, so it is expected that all creation
65             // succeeds even if the audio track is not explicitly created in offload mode.
66             val compressedProfiles = directProfiles.filterOutPcmFormats()
67             for (directProfile in compressedProfiles) {
68                 checkCreateAudioTracks(audioAttributes, directProfile, true)
69             }
70         }
71     }
72 
73     // Returns true if all the AudioTracks with all combinations of parameters that can be derived
74     // from the passed audio profile can be created with the expected result.
75     // Doesn't start the tracks.
76     private fun checkCreateAudioTracks(
77         audioAttributes: AudioAttributes,
78         audioProfile: AudioProfile,
79         expectedCreationSuccess: Boolean
80     ) {
81         if (audioProfile.format == AudioFormat.ENCODING_INVALID) {
82             fail("Found INVALID audio format in audio profile ($audioProfile) " +
83                     "when trying to create audio tracks with it!")
84         }
85         for (audioFormat in audioProfile.getAllAudioFormats()) {
86             try {
87                 AudioTrack.Builder()
88                     .setAudioAttributes(audioAttributes)
89                     .setAudioFormat(audioFormat)
90                     .build()
91                     .release()
92                 // allow a short time to free the AudioTrack resources
93                 Thread.sleep(100)
94                 if (!expectedCreationSuccess) {
95                     fail(
96                         "Created AudioTrack for attributes ($audioAttributes) and " +
97                                 "audio format ($audioFormat)!"
98                     )
99                 }
100             } catch (e: Exception) {
101                 if (expectedCreationSuccess) {
102                     fail(
103                         "Failed to create AudioTrack for attributes ($audioAttributes) and " +
104                                 "audio format ($audioFormat) with exception ($e)!"
105                     )
106                 }
107             }
108         }
109     }
110 
111     // Utils
112     private fun AudioProfile.getAllAudioFormats() =
113         sampleRates.map { sampleRate ->
114             channelMasks.map { channelMask ->
115                 AudioFormat.Builder()
116                     .setEncoding(format)
117                     .setSampleRate(sampleRate)
118                     .setChannelMask(channelMask)
119                     .build()
120             }.plus(
121                 channelIndexMasks.map { channelIndexMask ->
122                     AudioFormat.Builder()
123                         .setEncoding(format)
124                         .setSampleRate(sampleRate)
125                         .setChannelIndexMask(channelIndexMask)
126                         .build()
127                 }
128             )
129         }.flatten()
130 
131     private fun List<AudioProfile>.filterOutPcmFormats() = filter { it.format !in pcmFormats }
132 
133     companion object {
134         private val pcmFormats = listOf(
135             AudioFormat.ENCODING_PCM_8BIT,
136             AudioFormat.ENCODING_PCM_16BIT,
137             AudioFormat.ENCODING_PCM_FLOAT,
138             AudioFormat.ENCODING_PCM_24BIT_PACKED,
139             AudioFormat.ENCODING_PCM_32BIT
140         )
141     }
142 }
143