xref: /aosp_15_r20/cts/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestXheAac.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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 package android.media.decoder.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import android.app.Instrumentation;
25 import android.content.res.AssetFileDescriptor;
26 import android.content.res.Resources;
27 import android.media.MediaCodec;
28 import android.media.MediaCodecInfo;
29 import android.media.MediaCodecList;
30 import android.media.MediaExtractor;
31 import android.media.MediaFormat;
32 import android.media.cts.TestUtils;
33 import android.media.decoder.cts.DecoderTest.AudioParameter;
34 import android.media.decoder.cts.DecoderTestAacDrc.DrcParams;
35 import android.os.Build;
36 import android.os.Bundle;
37 import android.platform.test.annotations.AppModeFull;
38 import android.util.Log;
39 
40 import androidx.test.InstrumentationRegistry;
41 
42 import com.android.compatibility.common.util.ApiLevelUtil;
43 import com.android.compatibility.common.util.ApiTest;
44 import com.android.compatibility.common.util.CddTest;
45 import com.android.compatibility.common.util.MediaUtils;
46 
47 import org.junit.Before;
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 import org.junit.runners.JUnit4;
51 
52 import java.io.IOException;
53 import java.nio.ByteBuffer;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.List;
57 
58 @AppModeFull(reason = "DecoderTest is non-instant")
59 @RunWith(JUnit4.class)
60 public class DecoderTestXheAac {
61     private static final String TAG = "DecoderTestXheAac";
62 
63     private static final boolean sIsAndroidRAndAbove =
64             ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
65 
66     private Resources mResources;
67 
68     // list of all AAC decoders as enumerated through the MediaCodecList
69     // lazy initialization in setUp()
70     private static ArrayList<String> sAacDecoderNames;
71     private static String defaultAacDecoder = null;
72     @Before
setUp()73     public void setUp() throws Exception {
74         final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
75         assertNotNull(inst);
76         mResources = inst.getContext().getResources();
77         // build a list of all AAC decoders on which to run the test
78         if (sAacDecoderNames == null) {
79             sAacDecoderNames = initAacDecoderNames();
80         }
81     }
82 
initAacDecoderNames()83     protected static ArrayList<String> initAacDecoderNames() throws IOException {
84         ArrayList<String> aacDecoderNames = new ArrayList<String>(1);
85         // Default aac decoder (the one that gets created when createDecoderByType with AAC mime
86         // is called) is expected to pass all DRC tests
87         if (defaultAacDecoder != null) {
88             aacDecoderNames.add(defaultAacDecoder);
89         } else {
90             MediaCodec decoder = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
91             aacDecoderNames.add(decoder.getName());
92             defaultAacDecoder = decoder.getName();
93             decoder.release();
94         }
95         // Add all decoders that advertise support for AACObjectXHE profile as decoders that
96         // support xHE-AAC profile are expected to support DRC
97         MediaFormat format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000,
98                 2);
99         // Set both KEY_AAC_PROFILE and KEY_PROFILE as some codecs may only recognize one of
100         // these two keys
101         format.setInteger(MediaFormat.KEY_AAC_PROFILE,
102                 MediaCodecInfo.CodecProfileLevel.AACObjectXHE);
103         format.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectXHE);
104 
105         final MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
106         final MediaCodecInfo[] mediaCodecInfos = mediaCodecList.getCodecInfos();
107         for (MediaCodecInfo mediaCodecInfo : mediaCodecInfos) {
108             if (mediaCodecInfo.isAlias()) {
109                 continue;
110             }
111             if (mediaCodecInfo.isEncoder()) {
112                 continue;
113             }
114             final String codecName = mediaCodecInfo.getName();
115             final String[] mimeTypes = mediaCodecInfo.getSupportedTypes();
116             for (String mimeType : mimeTypes) {
117                 if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mimeType)) {
118                     MediaCodecInfo.CodecCapabilities caps = mediaCodecInfo.getCapabilitiesForType(
119                             mimeType);
120                     if (caps.isFormatSupported(format)) {
121                         if (!aacDecoderNames.contains(codecName)) {
122                             aacDecoderNames.add(codecName);
123                         }
124                     }
125                     break;
126                 }
127             }
128         }
129         return aacDecoderNames;
130     }
131 
132     /**
133      * Verify the correct decoding of USAC bitstreams with different MPEG-D DRC effect types.
134      */
135     @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"})
136     @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION",
137             "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR",
138             "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR",
139             "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
140             "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE"})
141     @Test
testDecodeUsacDrcEffectTypeM4a()142     public void testDecodeUsacDrcEffectTypeM4a() throws Exception {
143         Log.v(TAG, "START testDecodeUsacDrcEffectTypeM4a");
144 
145         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
146 
147         for (String aacDecName : sAacDecoderNames) {
148             try {
149                 runDecodeUsacDrcEffectTypeM4a(aacDecName);
150             } catch (Error err) {
151                 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
152             }
153         }
154     }
155 
runDecodeUsacDrcEffectTypeM4a(String aacDecName)156     private void runDecodeUsacDrcEffectTypeM4a(String aacDecName) throws Exception {
157         Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a running for dec=" + aacDecName);
158         // test DRC effectTypeID 1 "NIGHT"
159         // L -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
160         // R +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
161         try {
162             checkUsacDrcEffectType(1, 0.5011f, 1.9952f, "Night", 2, 0, aacDecName);
163         } catch (Exception e) {
164             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/0 failed for dec=" + aacDecName);
165             throw new RuntimeException(e);
166         }
167 
168         // test DRC effectTypeID 2 "NOISY"
169         // L +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
170         // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
171         try {
172             checkUsacDrcEffectType(2, 1.9952f, 0.2511f, "Noisy", 2, 0, aacDecName);
173         } catch (Exception e) {
174             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/0 failed for dec=" + aacDecName);
175             throw new RuntimeException(e);
176         }
177 
178         // test DRC effectTypeID 3 "LIMITED"
179         // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
180         // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
181         try {
182             checkUsacDrcEffectType(3, 0.2511f, 3.9810f, "Limited", 2, 0, aacDecName);
183         } catch (Exception e) {
184             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/0 failed for dec="
185                     + aacDecName);
186             throw new RuntimeException(e);
187         }
188 
189         // test DRC effectTypeID 6 "GENERAL"
190         // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
191         // R -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
192         try {
193             checkUsacDrcEffectType(6, 3.9810f, 0.5011f, "General", 2, 0, aacDecName);
194         } catch (Exception e) {
195             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/0 failed for dec="
196                     + aacDecName);
197             throw new RuntimeException(e);
198         }
199 
200         // test DRC effectTypeID 1 "NIGHT"
201         // L    -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
202         // R    +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
203         // mono -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
204         try {
205             checkUsacDrcEffectType(1, 0.2511f, 3.9810f, "Night", 2, 1, aacDecName);
206         } catch (Exception e) {
207             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
208             throw new RuntimeException(e);
209         }
210         try {
211             checkUsacDrcEffectType(1, 0.2511f, 0.0f, "Night", 1, 1, aacDecName);
212         } catch (Exception e) {
213             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/1/1 for dec=" + aacDecName);
214             throw new RuntimeException(e);
215         }
216 
217         // test DRC effectTypeID 2 "NOISY"
218         // L    +6dB -> normalization factor = 1/(10^( 6/10))   = 3.9810f
219         // R    -9dB -> normalization factor = 1/(10^(-9/10))  = 0.1258f
220         // mono +6dB -> normalization factor = 1/(10^( 6/10))   = 3.9810f
221         try {
222             checkUsacDrcEffectType(2, 3.9810f, 0.1258f, "Noisy", 2, 1, aacDecName);
223         } catch (Exception e) {
224             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/1 for dec=" + aacDecName);
225             throw new RuntimeException(e);
226         }
227         try {
228             checkUsacDrcEffectType(2, 3.9810f, 0.0f, "Noisy", 1, 1, aacDecName);
229         } catch (Exception e) {
230             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
231             throw new RuntimeException(e);
232         }
233 
234         // test DRC effectTypeID 3 "LIMITED"
235         // L    -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
236         // R    +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
237         // mono -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
238         try {
239             checkUsacDrcEffectType(3, 0.1258f, 7.9432f, "Limited", 2, 1, aacDecName);
240         } catch (Exception e) {
241             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/1 for dec=" + aacDecName);
242             throw new RuntimeException(e);
243         }
244         try {
245             checkUsacDrcEffectType(3, 0.1258f, 0.0f, "Limited", 1, 1, aacDecName);
246         } catch (Exception e) {
247             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/1/1 for dec=" + aacDecName);
248             throw new RuntimeException(e);
249         }
250 
251         // test DRC effectTypeID 6 "GENERAL"
252         // L    +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
253         // R    -6dB -> normalization factor = 1/(10^(-6/10))  = 0.2511f
254         // mono +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
255         try {
256             checkUsacDrcEffectType(6, 7.9432f, 0.2511f, "General", 2, 1, aacDecName);
257         } catch (Exception e) {
258             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/1 for dec=" + aacDecName);
259             throw new RuntimeException(e);
260         }
261         try {
262             checkUsacDrcEffectType(6, 7.9432f, 0.0f, "General", 1, 1, aacDecName);
263         } catch (Exception e) {
264             Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/1/1 for dec=" + aacDecName);
265             throw new RuntimeException(e);
266         }
267     }
268 
269     /**
270      * Verify the correct decoding of USAC bitstreams with album mode.
271      */
272     @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"})
273     @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION",
274             "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR",
275             "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR",
276             "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
277             "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE",
278             "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"})
279     @Test
testDecodeUsacDrcAlbumModeM4a()280     public void testDecodeUsacDrcAlbumModeM4a() throws Exception {
281         Log.v(TAG, "START testDecodeUsacDrcAlbumModeM4a");
282 
283         // Album mode is R feature
284         if (!MediaUtils.check(sIsAndroidRAndAbove, "Album mode support requires Android R"))
285                 return;
286 
287         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
288 
289         for (String aacDecName : sAacDecoderNames) {
290             try {
291                 runDecodeUsacDrcAlbumModeM4a(aacDecName);
292             } catch (Error err) {
293                 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
294             }
295         }
296     }
297 
runDecodeUsacDrcAlbumModeM4a(String aacDecName)298     private void runDecodeUsacDrcAlbumModeM4a(String aacDecName) throws Exception {
299         // test DRC Album Mode
300         // Track loudness = -19dB
301         // Album Loudness = -21 dB
302         // Fading Gains = -6 dB
303         // Album Mode ON : Gains = -24 - (-21) = -3dB
304         // Album Mode OFF : Gains = (-24 -(-19)) + (-6) = -11 dB
305         try {
306             checkUsacDrcAlbumMode(R.raw.noise_2ch_48khz_tlou_19lufs_alou_21lufs_mp4, aacDecName);
307         } catch (Exception e) {
308             Log.v(TAG, "testDecodeUsacDrcAlbumModeM4a for decoder" + aacDecName);
309             throw new RuntimeException(e);
310         }
311     }
312 
313     /**
314      * Verify the correct decoding of USAC bitstreams with config changes.
315      */
316     @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"})
317     @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION",
318             "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR",
319             "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR",
320             "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
321             "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE"})
322     @Test
testDecodeUsacStreamSwitchingM4a()323     public void testDecodeUsacStreamSwitchingM4a() throws Exception {
324         Log.v(TAG, "START testDecodeUsacStreamSwitchingM4a");
325 
326         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
327 
328         for (String aacDecName : sAacDecoderNames) {
329             try {
330                 runDecodeUsacStreamSwitchingM4a(aacDecName);
331             } catch (Error err) {
332                 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
333             }
334         }
335     }
336 
runDecodeUsacStreamSwitchingM4a(String aacDecName)337     private void runDecodeUsacStreamSwitchingM4a(String aacDecName) throws Exception {
338         // Stereo
339         // switch between SBR ratios and stereo modes
340         try {
341             checkUsacStreamSwitching(2.5459829E12f, 2,
342                     R.raw.noise_2ch_44_1khz_aot42_19_lufs_config_change_mp4, aacDecName);
343         } catch (Exception e) {
344             Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch sbr/stereo switch for "
345                     + aacDecName);
346             throw new RuntimeException(e);
347         }
348 
349         // Mono
350         // switch between SBR ratios and stereo modes
351         try {
352             checkUsacStreamSwitching(2.24669126E12f, 1,
353                     R.raw.noise_1ch_38_4khz_aot42_19_lufs_config_change_mp4, aacDecName);
354         } catch (Exception e) {
355             Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch sbr/stereo switch for "
356                     + aacDecName);
357             throw new RuntimeException(e);
358         }
359 
360         // Stereo
361         // switch between USAC modes
362         try {
363             checkUsacStreamSwitching(2.1E12f, 2,
364                     R.raw.noise_2ch_35_28khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
365         } catch (Exception e) {
366             Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch USAC mode switch for "
367                     + aacDecName);
368             throw new RuntimeException(e);
369         }
370 
371         // Mono
372         // switch between USAC modes
373         try {
374             checkUsacStreamSwitching(1.7E12f, 1,
375                     R.raw.noise_1ch_29_4khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
376         } catch (Exception e) {
377             Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch USAC mode switch for "
378                     + aacDecName);
379             throw new RuntimeException(e);
380         }
381 
382     }
383 
384     /**
385      * Verify the correct decoding of USAC bitstreams with various sampling rates.
386      */
387     @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"})
388     @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION",
389             "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR",
390             "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR",
391             "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
392             "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE"})
393     @Test
testDecodeUsacSamplingRatesM4a()394     public void testDecodeUsacSamplingRatesM4a() throws Exception {
395         Log.v(TAG, "START testDecodeUsacSamplingRatesM4a");
396 
397         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
398 
399         for (String aacDecName : sAacDecoderNames) {
400             try {
401                 runDecodeUsacSamplingRatesM4a(aacDecName);
402             } catch (Error err) {
403                 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
404             }
405         }
406     }
407 
runDecodeUsacSamplingRatesM4a(String aacDecName)408     private void runDecodeUsacSamplingRatesM4a(String aacDecName) throws Exception {
409         try {
410             checkUsacSamplingRate(R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, aacDecName);
411             checkUsacSamplingRate(R.raw.noise_2ch_12khz_aot42_19_lufs_mp4, aacDecName);
412             checkUsacSamplingRate(R.raw.noise_2ch_22_05khz_aot42_19_lufs_mp4, aacDecName);
413             checkUsacSamplingRate(R.raw.noise_2ch_64khz_aot42_19_lufs_mp4, aacDecName);
414             checkUsacSamplingRate(R.raw.noise_2ch_88_2khz_aot42_19_lufs_mp4, aacDecName);
415             checkUsacSamplingRateWoLoudness(R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4,
416                     aacDecName);
417         } catch (Exception e) {
418             Log.v(TAG, "testDecodeUsacSamplingRatesM4a for decoder" + aacDecName);
419             throw new RuntimeException(e);
420         }
421     }
422 
423     /**
424      * Verify the correct decoding of USAC bitstreams with different boost and attenuation settings
425      */
426     @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"})
427     @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION",
428             "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR",
429             "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR",
430             "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
431             "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE",
432             "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"})
433     @Test
testDecodeUsacDrcBoostAndAttenuationM4a()434     public void testDecodeUsacDrcBoostAndAttenuationM4a() throws Exception {
435         Log.v(TAG, "START testDecodeUsacDrcBoostAndAttenuationM4a");
436 
437         if (!MediaUtils.check(sIsAndroidRAndAbove, "Att/Boost corrected in Android R"))
438             return;
439 
440         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
441 
442         for (String aacDecName : sAacDecoderNames) {
443             try {
444                 runDecodeUsacDrcBoostAndAttenuationM4a(aacDecName);
445             } catch (Error err) {
446                 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
447             }
448         }
449     }
450 
runDecodeUsacDrcBoostAndAttenuationM4a(String aacDecName)451     private void runDecodeUsacDrcBoostAndAttenuationM4a(String aacDecName) throws Exception {
452         Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a running for dec=" + aacDecName);
453         // test drcBoost and drcAttenuation parameters
454         // DRC effectTypeID 6 "GENERAL"
455         // L +6dB -> normalization factor = 10^(6/10 * (1 - boostFactor:64/127)) = 1.9844f
456         // R -3dB -> normalization factor = 10^(-3/10 * (1 - attenuationFactor:127/127)) = 1.0f
457         try {
458             checkUsacDrcBoostAndAttenuation(1.9844f, 1.0f, 64, 127, 2, aacDecName);
459         } catch (Exception e) {
460             Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a failed for dec=" + aacDecName);
461             throw new RuntimeException(e);
462         }
463 
464         // test drcBoost and drcAttenuation parameters
465         // DRC effectTypeID 6 "GENERAL"
466         // L +6dB -> normalization factor = 10^(6/10 * (1 - boostFactor:127/127)) = 1.0f
467         // R -3dB -> normalization factor = 10^(-3/10 * (1 - attenuationFactor:64/127)) = 0.7099f
468         try {
469             checkUsacDrcBoostAndAttenuation(1.0f, 0.7099f, 127, 64, 2, aacDecName);
470         } catch (Exception e) {
471             Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a failed for dec=" + aacDecName);
472             throw new RuntimeException(e);
473         }
474 
475         // test drcBoost and drcAttenuation parameters
476         // DRC effectTypeID 6 "GENERAL"
477         // L +6dB -> normalization factor = 10^(6/10 * (1 - boostFactor:0/127)) = 3.9811f
478         // R -3dB -> normalization factor = 10^(-3/10 * (1 - attenuationFactor:127/127)) = 1.0f
479         try {
480             checkUsacDrcBoostAndAttenuation(3.9811f, 1.0f, 0, 127, 2, aacDecName);
481         } catch (Exception e) {
482             Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a failed for dec=" + aacDecName);
483             throw new RuntimeException(e);
484         }
485 
486         // test drcBoost and drcAttenuation parameters
487         // DRC effectTypeID 6 "GENERAL"
488         // L +6dB -> normalization factor = 10^(6/10 * (1 - boostFactor:127/127)) = 1.0f
489         // R -3dB -> normalization factor = 10^(-3/10 * (1 - attenuationFactor:0/127)) = 0.5012f
490         try {
491             checkUsacDrcBoostAndAttenuation(1.0f, 0.5012f, 127, 0, 2, aacDecName);
492         } catch (Exception e) {
493             Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a failed for dec=" + aacDecName);
494             throw new RuntimeException(e);
495         }
496     }
497 
498     /**
499      * verify the correct decoding of USAC bitstreams when different kinds of loudness values
500      * are present
501      */
502     @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"})
503     @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION",
504             "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR",
505             "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR",
506             "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
507             "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE",
508             "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"})
509     @Test
testDecodeUsacDrcLoudnessPreferenceM4a()510     public void testDecodeUsacDrcLoudnessPreferenceM4a() throws Exception {
511         Log.v(TAG, "START testDecodeUsacDrcLoudnessPreferenceM4a");
512 
513         if (!MediaUtils.check(sIsAndroidRAndAbove, "Loudness preference in Android R"))
514             return;
515 
516         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
517 
518         for (String aacDecName : sAacDecoderNames) {
519             try {
520                 runDecodeUsacDrcLoudnessPreferenceM4a(aacDecName);
521             } catch (Error err) {
522                 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
523             }
524         }
525     }
526 
runDecodeUsacDrcLoudnessPreferenceM4a(String aacDecName)527     private void runDecodeUsacDrcLoudnessPreferenceM4a(String aacDecName) throws Exception {
528         Log.v(TAG, "testDecodeUsacDrcLoudnessPreferenceM4a running for dec=" + aacDecName);
529         // test drc loudness preference
530         // anchor loudness (-17 LUFS) and program loudness (-19 LUFS) are present in one stream
531         // -> anchor loudness should be selected
532         // the bitstream is decoded with targetLoudnessLevel = -16 LUFS and
533         // checked against the energy of the decoded signal without loudness normalization
534         // normfactor = loudness of waveform - targetLoudnessLevel = -1dB = 0.7943
535         try {
536             checkUsacDrcLoudnessPreference(
537                     R.raw.noise_2ch_48khz_tlou_19lufs_anchor_17lufs_mp4, 0.7943f, aacDecName);
538         } catch (Exception e) {
539             Log.v(TAG, "testDecodeUsacDrcLoudnessPreferenceM4a failed for dec=" + aacDecName);
540             throw new RuntimeException(e);
541         }
542 
543         // test drc loudness preference
544         // expert loudness (-23 LUFS) and program loudness (-19 LUFS) are present in one stream
545         // -> expert loudness should be selected
546         // the bitstream is decoded with targetLoudnessLevel = -16 LUFS and
547         // checked against the energy of the decoded signal without loudness normalization
548         // normfactor = loudness of waveform - targetLoudnessLevel = -7dB = 0.1995
549         try {
550             checkUsacDrcLoudnessPreference(
551                     R.raw.noise_2ch_48khz_tlou_19lufs_expert_23lufs_mp4, 0.1995f, aacDecName);
552         } catch (Exception e) {
553             Log.v(TAG, "testDecodeUsacDrcLoudnessPreferenceM4a failed for dec=" + aacDecName);
554             throw new RuntimeException(e);
555         }
556     }
557 
558     /**
559      * Verify that the correct output loudness values are returned when decoding USAC bitstreams
560      */
561     @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"})
562     @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION",
563             "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR",
564             "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR",
565             "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
566             "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE",
567             "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"})
568     @Test
testDecodeUsacDrcOutputLoudnessM4a()569     public void testDecodeUsacDrcOutputLoudnessM4a() throws Exception {
570         Log.v(TAG, "START testDecodeUsacDrcOutputLoudnessM4a");
571 
572         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
573 
574         for (String aacDecName : sAacDecoderNames) {
575             try {
576                 runDecodeUsacDrcOutputLoudnessM4a(aacDecName);
577             } catch (Error err) {
578                 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
579             }
580         }
581     }
582 
runDecodeUsacDrcOutputLoudnessM4a(String aacDecName)583     private void runDecodeUsacDrcOutputLoudnessM4a(String aacDecName) throws Exception {
584         Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a running for dec=" + aacDecName);
585         // test drc output loudness
586         // testfile without loudness metadata and loudness normalization off -> expected value: -1
587         try {
588             checkUsacDrcOutputLoudness(
589                     R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4, -1, -1, aacDecName);
590         } catch (Exception e) {
591             Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName);
592             throw new RuntimeException(e);
593         }
594 
595         Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a running for dec=" + aacDecName);
596         // test drc output loudness
597         // testfile without loudness metadata and loudness normalization on
598         // -> expected value: -1
599         try {
600             checkUsacDrcOutputLoudness(
601                     R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4, 64, -1, aacDecName);
602         } catch (Exception e) {
603             Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName);
604             throw new RuntimeException(e);
605         }
606 
607         // test drc output loudness
608         // testfile with MPEG-D DRC loudness metadata and loudness normalization off
609         // -> expected value: loudness metadata in bitstream (-19*-4 = 76)
610         try {
611             checkUsacDrcOutputLoudness(
612                     R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, -1, 76, aacDecName);
613         } catch (Exception e) {
614             Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName);
615             throw new RuntimeException(e);
616         }
617 
618         // test drc output loudness
619         // testfile with MPEG-D DRC loudness metadata and loudness normalization off
620         // -> expected value: loudness metadata in bitstream (-22*-4 = 88)
621         try {
622             checkUsacDrcOutputLoudness(
623                     R.raw.noise_1ch_38_4khz_aot42_19_lufs_config_change_mp4, -1, 88, aacDecName);
624         } catch (Exception e) {
625             Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName);
626             throw new RuntimeException(e);
627         }
628 
629         // test drc output loudness
630         // testfile with MPEG-D DRC loudness metadata and loudness normalization on
631         // -> expected value: target loudness value (92)
632         try {
633             checkUsacDrcOutputLoudness(
634                     R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, 92, 92, aacDecName);
635         } catch (Exception e) {
636             Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName);
637             throw new RuntimeException(e);
638         }
639     }
640 
641 
642     /**
643      * Verify that seeking works correctly for USAC.
644      * Sync samples have to be taken into consideration.
645      */
646     @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"})
647     @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION",
648             "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR",
649             "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR",
650             "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
651             "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE",
652             "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"})
653     @Test
testDecodeUsacSyncSampleSeekingM4a()654     public void testDecodeUsacSyncSampleSeekingM4a() throws Exception {
655         Log.v(TAG, "START testDecodeUsacSyncSampleSeekingM4a");
656         if(!sIsAndroidRAndAbove) {
657             // The fix for b/158471477 was released in mainline release 300802800
658             // See https://android-build.googleplex.com/builds/treetop/googleplex-android-review/11990700
659             final int MIN_VERSION = 300802800;
660             TestUtils.assumeMainlineModuleAtLeast("com.google.android.media.swcodec", MIN_VERSION);
661             TestUtils.assumeMainlineModuleAtLeast("com.google.android.media", MIN_VERSION);
662         }
663 
664         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
665 
666         for (String aacDecName : sAacDecoderNames) {
667             try {
668                 runDecodeUsacSyncSampleSeekingM4a(aacDecName);
669             } catch (Error err) {
670                 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
671             }
672         }
673     }
674 
runDecodeUsacSyncSampleSeekingM4a(String aacDecName)675     private void runDecodeUsacSyncSampleSeekingM4a(String aacDecName) throws Exception {
676         Log.v(TAG, "testDecodeUsacSyncSampleSeekingM4a running for dec=" + aacDecName);
677         // test usac seeking
678         try {
679             checkUsacSyncSampleSeeking(R.raw.sine_2ch_48khz_aot42_seek_mp4, aacDecName);
680         } catch (Exception e) {
681             Log.v(TAG, "testDecodeUsacSyncSampleSeekingM4a failed for dec=" + aacDecName);
682             throw new RuntimeException(e);
683         }
684         Log.v(TAG, "testDecodeUsacSyncSampleSeekingM4a running for dec=" + aacDecName);
685     }
686 
687     /**
688      *  Internal utilities
689      */
690 
691     /**
692      * USAC test DRC Effect Type
693      */
checkUsacDrcEffectType(int effectTypeID, float normFactor_L, float normFactor_R, String effectTypeName, int nCh, int aggressiveDrc, String decoderName)694     private void checkUsacDrcEffectType(int effectTypeID, float normFactor_L, float normFactor_R,
695                  String effectTypeName, int nCh, int aggressiveDrc, String decoderName)
696                          throws Exception {
697         for (boolean runtimeChange : new boolean[] {false, true}) {
698             if (runtimeChange && !sIsAndroidRAndAbove) {
699                 // changing decoder configuration after it has been initialized requires R and above
700                 continue;
701             }
702             int testinput = -1;
703             AudioParameter decParams = new AudioParameter();
704             DrcParams drcParams_def  = new DrcParams(127, 127, 96, 0, -1);
705             DrcParams drcParams_test = new DrcParams(127, 127, 96, 0, effectTypeID);
706 
707             if (aggressiveDrc == 0) {
708                 testinput = R.raw.noise_2ch_32khz_aot42_19_lufs_drc_mp4;
709             } else {
710                 if (nCh == 2) {
711                     testinput = R.raw.noise_2ch_35_28khz_aot42_19_lufs_drc_config_change_mp4;
712                 } else if (nCh == 1){
713                     testinput = R.raw.noise_1ch_29_4khz_aot42_19_lufs_drc_config_change_mp4;
714                 }
715             }
716 
717             short[] decSamples_def  = decodeToMemory(decParams, testinput,
718                     -1, null, drcParams_def, decoderName);
719             short[] decSamples_test = decodeToMemory(decParams, testinput,
720                     -1, null, drcParams_test, decoderName, runtimeChange);
721 
722             float[] nrg_def  = checkEnergyUSAC(decSamples_def, decParams, nCh, 1, 0);
723             float[] nrg_test = checkEnergyUSAC(decSamples_test, decParams, nCh, 1, 1);
724 
725             if (nCh == 2) {
726                 float nrgRatio_L = (nrg_test[1]/nrg_def[1])/normFactor_L;
727                 float nrgRatio_R = (nrg_test[2]/nrg_def[2])/normFactor_R;
728                 if ((nrgRatio_R > 1.05f || nrgRatio_R < 0.95f)
729                         || (nrgRatio_L > 1.05f || nrgRatio_L < 0.95f) ){
730                     throw new Exception("DRC Effect Type '" + effectTypeName + "' not as expected");
731                 }
732             } else if (nCh == 1){
733                 float nrgRatio_L = (nrg_test[0]/nrg_def[0])/normFactor_L;
734                 if (nrgRatio_L > 1.05f || nrgRatio_L < 0.95f){
735                     throw new Exception("DRC Effect Type '" + effectTypeName + "' not as expected");
736                 }
737             }
738         }
739     }
740 
741     /**
742      * USAC test stream switching
743      */
checkUsacStreamSwitching(float nrg_ref, int encNch, int testinput, String decoderName)744     private void checkUsacStreamSwitching(float nrg_ref, int encNch, int testinput,
745             String decoderName) throws Exception
746     {
747         AudioParameter decParams = new AudioParameter();
748         DrcParams drcParams      = new DrcParams(127, 127, 64, 0, -1);
749 
750         // Check stereo stream switching
751         short[] decSamples = decodeToMemory(decParams, testinput,
752                 -1, null, drcParams, decoderName);
753         float[] nrg = checkEnergyUSAC(decSamples, decParams, encNch, 1);
754 
755         float nrgRatio = nrg[0] / nrg_ref;
756 
757         // Check if energy levels are within 15% of the reference
758         // Energy drops within the decoded stream are checked by checkEnergyUSAC() within every
759         // 250ms interval
760         if (nrgRatio > 1.15f || nrgRatio < 0.85f ) {
761             throw new Exception("Config switching not as expected");
762         }
763     }
764 
765     /**
766      * USAC test sampling rate
767      */
checkUsacSamplingRate(int testinput, String decoderName)768     private void checkUsacSamplingRate(int testinput, String decoderName) throws Exception {
769         AudioParameter decParams  = new AudioParameter();
770         DrcParams drcParams_def   = new DrcParams(127, 127, 64, 0, -1);
771         DrcParams drcParams_test  = new DrcParams(127, 127, 96, 0, -1);
772 
773         short[] decSamples_def  = decodeToMemory(decParams, testinput,
774                 -1, null, drcParams_def, decoderName);
775         short[] decSamples_test = decodeToMemory(decParams, testinput,
776                 -1, null, drcParams_test, decoderName);
777 
778         float[] nrg_def  = checkEnergyUSAC(decSamples_def, decParams, 2, 1);
779         float[] nrg_test = checkEnergyUSAC(decSamples_test, decParams, 2, 1);
780 
781         float nrgRatio = nrg_def[0]/nrg_test[0];
782 
783         // normFactor = 1/(10^(-8/10)) = 6.3f
784         nrgRatio = nrgRatio / 6.3f;
785 
786         // Check whether behavior is as expected
787         if (nrgRatio > 1.05f || nrgRatio < 0.95f ){
788             throw new Exception("Sampling rate not supported");
789         }
790     }
791 
792     /**
793      * USAC test sampling rate for streams without loudness application
794      */
checkUsacSamplingRateWoLoudness(int testinput, String decoderName)795     private void checkUsacSamplingRateWoLoudness(int testinput, String decoderName) throws Exception
796     {
797         AudioParameter decParams  = new AudioParameter();
798         DrcParams drcParams       = new DrcParams();
799 
800         short[] decSamples = decodeToMemory(decParams, testinput, -1, null, drcParams, decoderName);
801 
802         float[] nrg = checkEnergyUSAC(decSamples, decParams, 2, 1);
803 
804         float nrg_ref  = 3.15766394E12f;
805         float nrgRatio = nrg_ref/nrg[0];
806 
807         // Check whether behavior is as expected
808         if (nrgRatio > 1.05f || nrgRatio < 0.95f ){
809             throw new Exception("Sampling rate not supported");
810         }
811     }
812 
813     /**
814      * USAC test DRC Album Mode
815      */
checkUsacDrcAlbumMode(int testinput, String decoderName)816     private void checkUsacDrcAlbumMode(int testinput, String decoderName) throws Exception {
817         for (boolean runtimeChange : new boolean[] {false, true}) {
818             AudioParameter decParams = new AudioParameter();
819             DrcParams drcParams_album_off = new DrcParams(127, 127, 64, 0, 0, 0);
820             DrcParams drcParams_album_on  = new DrcParams(127, 127, 64, 0, 0, 1);
821 
822             short[] decSamples_album_off = decodeToMemory(
823                     decParams, testinput, -1, null, drcParams_album_off, decoderName);
824             short[] decSamples_album_on = decodeToMemory(
825                     decParams, testinput, -1, null, drcParams_album_on, decoderName, runtimeChange);
826 
827             float[] nrg_album_off  = checkEnergyUSAC(decSamples_album_off, decParams, 2, 1);
828             float[] nrg_album_on = checkEnergyUSAC(decSamples_album_on, decParams, 2, 1);
829 
830             float normFactor = 6.3095f;
831 
832             float nrgRatio = (nrg_album_on[0]/nrg_album_off[0])/normFactor;
833             float nrgRatio_L = (nrg_album_on[1]/nrg_album_off[1])/normFactor;
834             float nrgRatio_R = (nrg_album_on[2]/nrg_album_off[2])/normFactor;
835 
836             if (nrgRatio > 1.05f || nrgRatio < 0.95f ){
837                 throw new Exception("DRC Album Mode not supported, energy ratio " + nrgRatio);
838             }
839         }
840     }
841 
842     /**
843      * USAC test DRC Boost and Attenuation
844      */
checkUsacDrcBoostAndAttenuation(float normFactor_L, float normFactor_R, int boostFactor, int attenuationFactor, int nCh, String decoderName)845     private void checkUsacDrcBoostAndAttenuation(float normFactor_L, float normFactor_R,
846                                                  int boostFactor, int attenuationFactor,
847                                                  int nCh, String decoderName) throws Exception {
848         for (boolean runtimeChange : new boolean[] {false, true}) {
849             if (runtimeChange && !sIsAndroidRAndAbove) {
850                 // changing decoder configuration after it has been initialized requires R and above
851                 continue;
852             }
853 
854             int testinput = R.raw.noise_2ch_32khz_aot42_19_lufs_drc_mp4;
855 
856             AudioParameter decParams = new AudioParameter();
857             DrcParams drcParams_def = new DrcParams(127, 127, 64, 0, 6);
858             DrcParams drcParams_test = new DrcParams(boostFactor, attenuationFactor, 64, 0, 6);
859 
860             short[] decSamples_def = decodeToMemory(decParams, testinput, -1, null,
861                     drcParams_def, decoderName);
862             short[] decSamples_test = decodeToMemory(decParams, testinput, -1, null,
863                     drcParams_test, decoderName, runtimeChange);
864 
865             float[] nrg_def = checkEnergyUSAC(decSamples_def, decParams, 2, 1);
866             float[] nrg_test = checkEnergyUSAC(decSamples_test, decParams, 2, 1);
867 
868             float nrgRatioLeft = nrg_test[1] / nrg_def[1];
869             float nrgRatioRight = nrg_test[2] / nrg_def[2];
870 
871             float testValueLeft = normFactor_L * nrgRatioLeft;
872             float testValueRight = normFactor_R * nrgRatioRight;
873 
874             // Check whether loudness behavior is as expected
875             if (testValueLeft > 1.05f || testValueLeft < 0.95f) {
876                 throw new Exception("DRC boost/attenuation behavior not as expected");
877             }
878             if (testValueRight > 1.05f || testValueRight < 0.95f) {
879                 throw new Exception("DRC boost/attenuation behavior not as expected");
880             }
881         }
882     }
883 
884     /**
885     * USAC test Loudness Preference
886     */
checkUsacDrcLoudnessPreference(int testInput, float normFactor, String decoderName)887     private void checkUsacDrcLoudnessPreference(int testInput, float normFactor, String decoderName) throws Exception {
888 
889         AudioParameter decParams = new AudioParameter();
890         DrcParams drcParams_def = new DrcParams(127, 127, -1, 0, 6);
891         DrcParams drcParams_test = new DrcParams(127, 127, 64, 0, 6);
892 
893         // Check drc loudness preference
894         short[] decSamples_def = decodeToMemory(decParams, testInput, -1, null, drcParams_def, decoderName);
895         short[] decSamples_test = decodeToMemory(decParams, testInput, -1, null, drcParams_test, decoderName);
896 
897         float[] nrg_def  = checkEnergyUSAC(decSamples_def, decParams, 2, 1);
898         float[] nrg_test = checkEnergyUSAC(decSamples_test, decParams, 2, 1);
899 
900         float nrgRatio = (nrg_test[0]/nrg_def[0]);
901         nrgRatio = nrgRatio * normFactor;
902 
903         if (nrgRatio > 1.05f || nrgRatio < 0.95f ){
904             throw new Exception("DRC Loudness preference not as expected");
905         }
906     }
907 
908     /**
909     * USAC test Output Loudness
910     */
checkUsacDrcOutputLoudness(int testInput, int decoderTargetLevel, int expectedOutputLoudness, String decoderName)911     private void checkUsacDrcOutputLoudness(int testInput, int decoderTargetLevel,
912             int expectedOutputLoudness, String decoderName) throws Exception {
913         for (boolean runtimeChange : new boolean[] {false, true}) {
914             AudioParameter decParams = new AudioParameter();
915             DrcParams drcParams_test = new DrcParams(127, 127, decoderTargetLevel, 0, 6);
916 
917             // Check drc loudness preference
918             short[] decSamples_test = decodeToMemory(
919                     decParams, testInput, -1, null, drcParams_test,
920                     decoderName, runtimeChange, expectedOutputLoudness);
921         }
922     }
923 
checkUsacSyncSampleSeeking(int testInput, String decoderName)924     private void checkUsacSyncSampleSeeking(int testInput, String decoderName) throws Exception {
925 
926         AudioParameter decParams = new AudioParameter();
927         DrcParams drcParams_def = new DrcParams();
928 
929         short[] decSamples_seek_next_sync = decodeToMemory(decParams, testInput, -1, null,
930                 drcParams_def, decoderName, false, -2, true, 1100000,
931                 MediaExtractor.SEEK_TO_NEXT_SYNC);
932         float[] nrg_seek_next_sync = checkEnergyUSAC(decSamples_seek_next_sync, decParams, 2, 1);
933     }
934 
935     /**
936      * Perform a segmented energy analysis on given audio signal samples and run several tests on
937      * the energy values.
938      *
939      * The main purpose is to verify whether a USAC decoder implementation applies Spectral Band
940      * Replication (SBR), Parametric Stereo (PS) and Dynamic Range Control (DRC) correctly. All
941      * tools are inherent parts to either the MPEG-D USAC audio codec or the MPEG-D DRC tool.
942      *
943      * In addition, this test can verify the correct decoding of multi-channel (e.g. 5.1 channel)
944      * streams or the creation of a downmixed signal.
945      *
946      * Note: This test procedure is not an MPEG Conformance Test and can not serve as a replacement.
947      *
948      * @param decSamples the decoded audio samples to be tested
949      * @param decParams the audio parameters of the given audio samples (decSamples)
950      * @param encNch the encoded number of audio channels (number of channels of the original
951      *               input)
952      * @param drcContext indicate to use test criteria applicable for DRC testing
953      * @return array of energies, at index 0: accumulated energy of all channels, and
954      *     index 1 and over contain the individual channel energies
955      * @throws RuntimeException
956      */
checkEnergyUSAC(short[] decSamples, AudioParameter decParams, int encNch, int drcContext)957     protected float[] checkEnergyUSAC(short[] decSamples, AudioParameter decParams,
958                                       int encNch, int drcContext)
959     {
960         final float[] nrg = checkEnergyUSAC(decSamples, decParams, encNch, drcContext,  0);
961         return nrg;
962     }
963 
964     /**
965      * Same as {@link #checkEnergyUSAC(short[], AudioParameter, int, int)} but with DRC effect type
966      * @param decSamples
967      * @param decParams
968      * @param encNch
969      * @param drcContext
970      * @param drcApplied indicate if MPEG-D DRC Effect Type has been applied
971      * @return
972      * @throws RuntimeException
973      */
checkEnergyUSAC(short[] decSamples, AudioParameter decParams, int encNch, int drcContext, int drcApplied)974     private float[] checkEnergyUSAC(short[] decSamples, AudioParameter decParams,
975                                     int encNch, int drcContext,  int drcApplied)
976             throws RuntimeException
977     {
978         String localTag = TAG + "#checkEnergyUSAC";
979 
980         // the number of segments per block
981         final int nSegPerBlk = 4;
982         // the number of input channels
983         final int nCh = encNch;
984         // length of one (LB/HB) block [samples]
985         final int nBlkSmp = decParams.getSamplingRate();
986         // length of one segment [samples]
987         final int nSegSmp = nBlkSmp / nSegPerBlk;
988         // actual # samples per channel (total)
989         final int smplPerChan = decSamples.length / nCh;
990         // actual # samples per segment (all ch)
991         final int nSegSmpTot = nSegSmp * nCh;
992         // signal offset between chans [segments]
993         final int nSegChOffst = 2 * nSegPerBlk;
994         // // the number of channels to be analyzed
995         final int procNch = Math.min(nCh, encNch);
996         // all original configs with more than five channel have an LFE
997         final int encEffNch = (encNch > 5) ? encNch-1 : encNch;
998         // expected number of decoded audio samples
999         final int expSmplPerChan = Math.max(encEffNch, 2) * nSegChOffst * nSegSmp;
1000         // flag telling that input is dmx signal
1001         final boolean isDmx = nCh < encNch;
1002         final float nrgRatioThresh = 0.0f;
1003         // the num analyzed channels with signal
1004         int effProcNch = procNch;
1005 
1006         // get the signal offset by counting zero samples at the very beginning (over all channels)
1007         // sample value threshold 4 signal search
1008         final int zeroSigThresh = 1;
1009         // receives the number of samples that are in front of the actual signal
1010         int signalStart = smplPerChan;
1011         // receives the number of null samples (per chan) at the very beginning
1012         int noiseStart = signalStart;
1013 
1014         for (int smpl = 0; smpl < decSamples.length; smpl++) {
1015             int value = Math.abs(decSamples[smpl]);
1016 
1017             if (value > 0 && noiseStart == signalStart) {
1018                 // store start of prepended noise (can be same as signalStart)
1019                 noiseStart = smpl / nCh;
1020             }
1021 
1022             if (value > zeroSigThresh) {
1023                 // store signal start offset [samples]
1024                 signalStart = smpl / nCh;
1025                 break;
1026             }
1027         }
1028 
1029         signalStart = (signalStart > noiseStart+1) ? signalStart : noiseStart;
1030 
1031         // check if the decoder reproduced a waveform or kept silent
1032         assertTrue ("no signal found in any channel!", signalStart < smplPerChan);
1033 
1034         // max num seg that fit into signal
1035         final int totSeg = (smplPerChan - signalStart) / nSegSmp;
1036         // max num relevant samples (per channel)
1037         final int totSmp = nSegSmp * totSeg;
1038 
1039         // check if the number of reproduced segments in the audio file is valid
1040         assertTrue("no segments left to test after signal search", totSeg > 0);
1041 
1042         // get the energies and the channel offsets by searching for the first segment above the
1043         // energy threshold:
1044         // ratio of zeroNrgThresh to the max nrg
1045         final double zeroMaxNrgRatio = 0.001f;
1046         // threshold to classify segment energies
1047         double zeroNrgThresh = nSegSmp * nSegSmp;
1048         // will store the max seg nrg over all ch
1049         double totMaxNrg = 0.0f;
1050         // array receiving the segment energies
1051         double[][] nrg = new double[procNch][totSeg];
1052         // array for channel offsets
1053         int[] offset = new int[procNch];
1054         // array receiving the segment energy status over all channels
1055         boolean[] sigSeg = new boolean[totSeg];
1056         // energy per channel
1057         double[] nrgPerChannel = new double[procNch];
1058         // return value: [0]: total energy of all channels
1059         //               [1 ... procNch + 1]: energy of the individual channels
1060         float[] nrgTotal = new float[procNch + 1];
1061         // mapping array to sort channels
1062         int[] chMap = new int[nCh];
1063 
1064         // calculate the segmental energy for each channel
1065         for (int ch = 0; ch < procNch; ch++) {
1066             offset[ch] = -1;
1067 
1068             for (int seg = 0; seg < totSeg; seg++) {
1069                 final int smpStart = (signalStart * nCh) + (seg * nSegSmpTot) + ch;
1070                 final int smpStop = smpStart + nSegSmpTot;
1071 
1072                 for (int smpl = smpStart; smpl < smpStop; smpl += nCh) {
1073                     // accumulate total energy per channel
1074                     nrgPerChannel[ch] += decSamples[smpl] * decSamples[smpl];
1075                     // accumulate segment energy
1076                     nrg[ch][seg] += nrgPerChannel[ch];
1077                 }
1078 
1079                 // store 1st segment (index) per channel which has energy above the threshold to get
1080                 // the ch offsets
1081                 if (nrg[ch][seg] > zeroNrgThresh && offset[ch] < 0) {
1082                     offset[ch] = seg / nSegChOffst;
1083                 }
1084 
1085                 // store the max segment nrg over all ch
1086                 if (nrg[ch][seg] > totMaxNrg) {
1087                     totMaxNrg = nrg[ch][seg];
1088                 }
1089 
1090                 // store whether the channel has energy in this segment
1091                 sigSeg[seg] |= nrg[ch][seg] > zeroNrgThresh;
1092             }
1093 
1094             // if one channel has no signal it is most probably the LFE the LFE is no
1095             // effective channel
1096             if (offset[ch] < 0) {
1097                 effProcNch -= 1;
1098                 offset[ch] = effProcNch;
1099             }
1100 
1101             // recalculate the zero signal threshold based on the 1st channels max energy for
1102             // all subsequent checks
1103             if (ch == 0) {
1104                 zeroNrgThresh = zeroMaxNrgRatio * totMaxNrg;
1105             }
1106         }
1107 
1108         // check if the LFE is decoded properly
1109         assertTrue("more than one LFE detected", effProcNch >= procNch - 1);
1110 
1111         // check if the amount of samples is valid
1112         assertTrue(String.format("less samples decoded than expected: %d < %d",
1113                                  decSamples.length - (signalStart * nCh),
1114                                  totSmp * effProcNch),
1115                                  decSamples.length - (signalStart * nCh) >= totSmp * effProcNch);
1116 
1117         // for multi-channel signals the only valid front channel orders
1118         // are L, R, C or C, L, R (L=left, R=right, C=center)
1119         if (procNch >= 5) {
1120             final int[] frontChMap1 = {2, 0, 1};
1121             final int[] frontChMap2 = {0, 1, 2};
1122 
1123             // check if the channel mapping is valid
1124             if (!(Arrays.equals(Arrays.copyOfRange(offset, 0, 3), frontChMap1)
1125                     || Arrays.equals(Arrays.copyOfRange(offset, 0, 3), frontChMap2))) {
1126                 fail("wrong front channel mapping");
1127             }
1128         }
1129 
1130         // create mapping table to address channels from front to back the LFE must be last
1131         if (drcContext == 0) {
1132             // check whether every channel occurs exactly once
1133             for (int ch = 0; ch < effProcNch; ch++) {
1134                 int occurred = 0;
1135 
1136                 for (int idx = 0; idx < procNch; idx++) {
1137                     if (offset[idx] == ch) {
1138                         occurred += 1;
1139                         chMap[ch] = idx;
1140                     }
1141                 }
1142 
1143                 // check if one channel is mapped more than one time
1144                 assertTrue(String.format("channel %d occurs %d times in the mapping", ch, occurred),
1145                         occurred == 1);
1146             }
1147         } else {
1148             for (int ch = 0; ch < procNch; ch++) {
1149                 chMap[ch] = ch;
1150             }
1151         }
1152 
1153         // reference min energy for the 1st ch; others will be compared against 1st
1154         double refMinNrg = zeroNrgThresh;
1155 
1156         // calculate total energy, min and max energy
1157         for (int ch = 0; ch < procNch; ch++) {
1158             // resolve channel mapping
1159             int idx = chMap[ch];
1160             // signal offset [segments]
1161             final int ofst = offset[idx] * nSegChOffst;
1162 
1163             if (ch <= effProcNch && ofst < totSeg) {
1164                 // the last segment that has energy
1165                 int nrgSegEnd;
1166                 // the number of segments with energy
1167                 int nrgSeg;
1168 
1169                 if (drcContext == 0) {
1170 
1171                     // the first channel of a mono or stereo signal has full signal all others have
1172                     // one LB + one HB block
1173                     if ((encNch <= 2) && (ch == 0)) {
1174                         nrgSeg = totSeg;
1175                     } else {
1176                         nrgSeg = Math.min(totSeg, (2 * nSegPerBlk) + ofst) - ofst;
1177                     }
1178                 } else {
1179                     nrgSeg = totSeg;
1180                 }
1181 
1182                 nrgSegEnd = ofst + nrgSeg;
1183 
1184                 // find min and max energy of all segments that should have signal
1185                 double minNrg = nrg[idx][ofst]; // channels minimum segment energy
1186                 double maxNrg = nrg[idx][ofst]; // channels maximum segment energy
1187 
1188                 // values of 1st segment already assigned
1189                 for (int seg = ofst + 1; seg < nrgSegEnd; seg++) {
1190                     if (nrg[idx][seg] < minNrg) {
1191                         minNrg = nrg[idx][seg];
1192                     }
1193 
1194                     if (nrg[idx][seg] > maxNrg) {
1195                         maxNrg = nrg[idx][seg];
1196                     }
1197                 }
1198 
1199                 // check if the energy of this channel is > 0
1200                 assertTrue(String.format("max energy of channel %d is zero", ch),maxNrg > 0.0f);
1201 
1202                 if (drcContext == 0) {
1203                     // check the channels minimum energy >= refMinNrg
1204                     assertTrue(String.format("channel %d has not enough energy", ch),
1205                             minNrg >= refMinNrg);
1206 
1207                     if (ch == 0) {
1208                         // use 85% of 1st channels min energy as reference the other chs must meet
1209                         refMinNrg = minNrg * 0.85f;
1210                     } else if (isDmx && (ch == 1)) {
1211                         // in case of downmixed signal the energy can be lower depending on the
1212                         refMinNrg *= 0.50f;
1213                     }
1214 
1215                     // calculate and check the energy ratio
1216                     final double nrgRatio = minNrg / maxNrg;
1217 
1218                     // check if the threshold is exceeded
1219                     assertTrue(String.format("energy ratio of channel %d below threshold", ch),
1220                             nrgRatio >= nrgRatioThresh);
1221 
1222                     if (!isDmx) {
1223                         if (nrgSegEnd < totSeg) {
1224                             // consider that some noise can extend into the subsequent segment
1225                             // allow this to be at max 20% of the channels minimum energy
1226                             assertTrue(
1227                                     String.format("min energy after noise above threshold (%.2f)",
1228                                     nrg[idx][nrgSegEnd]),
1229                                     nrg[idx][nrgSegEnd] < minNrg * 0.20f);
1230                             nrgSegEnd += 1;
1231                         }
1232                     } else {
1233                         // ignore all subsequent segments in case of a downmixed signal
1234                         nrgSegEnd = totSeg;
1235                     }
1236 
1237                     // zero-out the verified energies to simplify the subsequent check
1238                     for (int seg = ofst; seg < nrgSegEnd; seg++) {
1239                         nrg[idx][seg] = 0.0f;
1240                     }
1241 
1242                     // check zero signal parts
1243                     for (int seg = 0; seg < totSeg; seg++) {
1244                         assertTrue(String.format("segment %d in channel %d has signal where should "
1245                                 + "be none (%.2f)", seg, ch, nrg[idx][seg]),
1246                                 nrg[idx][seg] < zeroNrgThresh);
1247                     }
1248                 }
1249             }
1250 
1251             // test whether each segment has energy in at least one channel
1252             for (int seg = 0; seg < totSeg; seg++) {
1253                 assertTrue(String.format("no channel has energy in segment %d", seg), sigSeg[seg]);
1254             }
1255 
1256             nrgTotal[0]     += (float)nrgPerChannel[ch];
1257             nrgTotal[ch + 1] = (float)nrgPerChannel[ch];
1258         }
1259 
1260         float errorMargin = 0.0f;
1261         if (drcApplied == 0) {
1262             errorMargin = 0.25f;
1263         } else if (drcApplied == 1) {
1264             errorMargin = 0.40f;
1265         }
1266 
1267         float totSegEnergy = 0.0f;
1268         float[] segEnergy = new float[totSeg];
1269         for (int seg = totSeg - 1; seg >= 0; seg--) {
1270             if (seg != 0) {
1271                 for (int ch = 0; ch < nCh; ch++) {
1272                     segEnergy[seg] += nrg[ch][seg] - nrg[ch][seg - 1];
1273                 }
1274                 totSegEnergy += segEnergy[seg];
1275             } else {
1276                 for (int ch = 0; ch < nCh; ch++) {
1277                     segEnergy[seg] += nrg[ch][seg];
1278                 }
1279             }
1280         }
1281         float avgSegEnergy = totSegEnergy / (totSeg - 1);
1282         for (int seg = 1; seg < totSeg; seg++) {
1283             float energyRatio = segEnergy[seg] / avgSegEnergy;
1284             if ((energyRatio > (1.0f + errorMargin) ) || (energyRatio < (1.0f - errorMargin) )) {
1285                 fail("Energy drop out");
1286             }
1287         }
1288 
1289         // return nrgTotal: [0]: accumulated energy of all channels, [1 ... ] channel energies
1290         return nrgTotal;
1291     }
1292 
1293     /**
1294      * Decodes a compressed bitstream in the ISOBMFF into the RAM of the device.
1295      *
1296      * The decoder decodes compressed audio data as stored in the ISO Base Media File Format
1297      * (ISOBMFF) aka .mp4/.m4a. The decoder is not reproducing the waveform but stores the decoded
1298      * samples in the RAM of the device under test.
1299      *
1300      * @param audioParams the decoder parameter configuration
1301      * @param testinput the compressed audio stream
1302      * @param eossample the End-Of-Stream indicator
1303      * @param timestamps the time stamps to decode
1304      * @param drcParams the MPEG-D DRC decoder parameter configuration
1305      * @param decoderName if non null, the name of the decoder to use for the decoding, otherwise
1306      *     the default decoder for the format will be used
1307      * @param runtimeChange defines whether the decoder is configured at runtime or configured
1308      *                      before starting to decode
1309      * @param expectedOutputLoudness value to check if the correct output loudness is returned
1310      *     by the decoder
1311      * @param seek_enable defines whether there will be an initial seek
1312      * @param seek_duration seeking duration in microseconds
1313      * @param seek_mode seeking mode
1314      *
1315      * @throws RuntimeException
1316      */
1317     public short[] decodeToMemory(AudioParameter audioParams, int testinput, int eossample,
1318             List<Long> timestamps, DrcParams drcParams, String decoderName, boolean runtimeChange,
1319             int expectedOutputLoudness,
1320             boolean seek_enable, int seek_duration, int seek_mode) throws IOException {
1321         // TODO: code is the same as in DecoderTest, differences are:
1322         //          - addition of application of DRC parameters
1323         //          - no need/use of resetMode, configMode
1324         //       Split method so code can be shared
1325 
1326         final String localTag = TAG + "#decodeToMemory";
1327         short [] decoded = new short[0];
1328         int decodedIdx = 0;
1329 
1330         AssetFileDescriptor testFd = mResources.openRawResourceFd(testinput);
1331 
1332         MediaExtractor extractor;
1333         MediaCodec codec;
1334         ByteBuffer[] codecInputBuffers;
1335         ByteBuffer[] codecOutputBuffers;
1336 
1337         extractor = new MediaExtractor();
1338         extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
1339                 testFd.getLength());
1340         testFd.close();
1341 
1342         assertEquals("wrong number of tracks", 1, extractor.getTrackCount());
1343         MediaFormat format = extractor.getTrackFormat(0);
1344         String mime = format.getString(MediaFormat.KEY_MIME);
1345         assertTrue("not an audio file", mime.startsWith("audio/"));
1346 
1347         MediaFormat configFormat = format;
1348         if (decoderName == null) {
1349             codec = MediaCodec.createDecoderByType(mime);
1350         } else {
1351             codec = MediaCodec.createByCodecName(decoderName);
1352         }
1353 
1354         // set DRC parameters
1355         if (drcParams != null) {
1356             configFormat.setInteger(MediaFormat.KEY_AAC_DRC_HEAVY_COMPRESSION, drcParams.mHeavy);
1357             if (!runtimeChange) {
1358                 configFormat.setInteger(MediaFormat.KEY_AAC_DRC_BOOST_FACTOR, drcParams.mBoost);
1359                 configFormat.setInteger(MediaFormat.KEY_AAC_DRC_ATTENUATION_FACTOR, drcParams.mCut);
1360                 if (drcParams.mDecoderTargetLevel != 0) {
1361                     configFormat.setInteger(MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL,
1362                             drcParams.mDecoderTargetLevel);
1363                 }
1364                 if (drcParams.mEffectType != 0){
1365                     configFormat.setInteger(MediaFormat.KEY_AAC_DRC_EFFECT_TYPE,
1366                             drcParams.mEffectType);
1367                 }
1368                 if (drcParams.mAlbumMode != 0) {
1369                     configFormat.setInteger(MediaFormat.KEY_AAC_DRC_ALBUM_MODE,
1370                             drcParams.mAlbumMode);
1371                 }
1372             }
1373         }
1374 
1375         Log.v(localTag, "configuring with " + configFormat);
1376         codec.configure(configFormat, null /* surface */, null /* crypto */, 0 /* flags */);
1377 
1378         if (drcParams != null && sIsAndroidRAndAbove) { // querying output format requires R
1379             if(!runtimeChange) {
1380                 if (drcParams.mAlbumMode != 0) {
1381                     int albumModeFromCodec = DecoderTest.getOutputFormatInteger(codec,
1382                             MediaFormat.KEY_AAC_DRC_ALBUM_MODE);
1383                     if (albumModeFromCodec != drcParams.mAlbumMode) {
1384                         fail("Drc AlbumMode received from MediaCodec is not the Album Mode set");
1385                     }
1386                 }
1387                 if (drcParams.mEffectType != 0) {
1388                     final int effectTypeFromCodec = DecoderTest.getOutputFormatInteger(codec,
1389                             MediaFormat.KEY_AAC_DRC_EFFECT_TYPE);
1390                     if (effectTypeFromCodec != drcParams.mEffectType) {
1391                         fail("Drc Effect Type received from MediaCodec is not the Effect Type set");
1392                     }
1393                 }
1394                 if (drcParams.mDecoderTargetLevel != 0) {
1395                     final int targetLevelFromCodec = DecoderTest.getOutputFormatInteger(codec,
1396                             MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL);
1397                     if (targetLevelFromCodec != drcParams.mDecoderTargetLevel) {
1398                         fail("Drc Target Reference Level received from MediaCodec is not the Target Reference Level set");
1399                     }
1400                 }
1401             }
1402         }
1403 
1404         codec.start();
1405         codecInputBuffers = codec.getInputBuffers();
1406         codecOutputBuffers = codec.getOutputBuffers();
1407 
1408         if (drcParams != null) {
1409             if (runtimeChange) {
1410                 Bundle b = new Bundle();
1411                 b.putInt(MediaFormat.KEY_AAC_DRC_BOOST_FACTOR, drcParams.mBoost);
1412                 b.putInt(MediaFormat.KEY_AAC_DRC_ATTENUATION_FACTOR, drcParams.mCut);
1413                 if (drcParams.mEffectType != 0) {
1414                     b.putInt(MediaFormat.KEY_AAC_DRC_EFFECT_TYPE, drcParams.mEffectType);
1415                 }
1416                 if (drcParams.mDecoderTargetLevel != 0) {
1417                     b.putInt(MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL,
1418                             drcParams.mDecoderTargetLevel);
1419                 }
1420                 if (drcParams.mAlbumMode != 0) {
1421                     b.putInt(MediaFormat.KEY_AAC_DRC_ALBUM_MODE, drcParams.mAlbumMode);
1422                 }
1423                 codec.setParameters(b);
1424             }
1425         }
1426 
1427         extractor.selectTrack(0);
1428 
1429         // execute initial seeking if specified
1430         if (seek_enable) {
1431             codec.flush();
1432             extractor.seekTo(seek_duration, seek_mode);
1433         }
1434 
1435         // start decoding
1436         final long kTimeOutUs = 5000;
1437         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
1438         boolean sawInputEOS = false;
1439         boolean sawOutputEOS = false;
1440         int noOutputCounter = 0;
1441         int samplecounter = 0;
1442 
1443         // main decoding loop
1444         while (!sawOutputEOS && noOutputCounter < 50) {
1445             noOutputCounter++;
1446             if (!sawInputEOS) {
1447                 int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
1448 
1449                 if (inputBufIndex >= 0) {
1450                     ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
1451 
1452                     int sampleSize =
1453                         extractor.readSampleData(dstBuf, 0 /* offset */);
1454 
1455                     long presentationTimeUs = 0;
1456 
1457                     if (sampleSize < 0 && eossample > 0) {
1458                         fail("test is broken: never reached eos sample");
1459                     }
1460 
1461                     if (sampleSize < 0) {
1462                         Log.d(TAG, "saw input EOS.");
1463                         sawInputEOS = true;
1464                         sampleSize = 0;
1465                     } else {
1466                         if (samplecounter == eossample) {
1467                             sawInputEOS = true;
1468                         }
1469                         samplecounter++;
1470                         presentationTimeUs = extractor.getSampleTime();
1471                     }
1472 
1473                     codec.queueInputBuffer(
1474                             inputBufIndex,
1475                             0 /* offset */,
1476                             sampleSize,
1477                             presentationTimeUs,
1478                             sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
1479 
1480                     if (!sawInputEOS) {
1481                         extractor.advance();
1482                     }
1483                 }
1484             }
1485 
1486             int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
1487 
1488             if (res >= 0) {
1489                 //Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs);
1490 
1491                 if (info.size > 0) {
1492                     noOutputCounter = 0;
1493                     if (timestamps != null) {
1494                         timestamps.add(info.presentationTimeUs);
1495                     }
1496                 }
1497 
1498                 int outputBufIndex = res;
1499                 ByteBuffer buf = codecOutputBuffers[outputBufIndex];
1500 
1501                 if (decodedIdx + (info.size / 2) >= decoded.length) {
1502                     decoded = Arrays.copyOf(decoded, decodedIdx + (info.size / 2));
1503                 }
1504 
1505                 buf.position(info.offset);
1506                 for (int i = 0; i < info.size; i += 2) {
1507                     decoded[decodedIdx++] = buf.getShort();
1508                 }
1509 
1510                 codec.releaseOutputBuffer(outputBufIndex, false /* render */);
1511 
1512                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
1513                     Log.d(TAG, "saw output EOS.");
1514                     sawOutputEOS = true;
1515                 }
1516             } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
1517                 codecOutputBuffers = codec.getOutputBuffers();
1518 
1519                 Log.d(TAG, "output buffers have changed.");
1520             } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
1521                 MediaFormat oformat = codec.getOutputFormat();
1522                 audioParams.setNumChannels(oformat.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
1523                 audioParams.setSamplingRate(oformat.getInteger(MediaFormat.KEY_SAMPLE_RATE));
1524                 Log.d(TAG, "output format has changed to " + oformat);
1525             } else {
1526                 Log.d(TAG, "dequeueOutputBuffer returned " + res);
1527             }
1528         }
1529 
1530         if (noOutputCounter >= 50) {
1531             fail("decoder stopped outputting data");
1532         }
1533 
1534         // check if MediaCodec gives back correct drc parameters
1535         if (drcParams != null && sIsAndroidRAndAbove) {
1536             if (drcParams.mAlbumMode != 0) {
1537                 final int albumModeFromCodec = DecoderTest.getOutputFormatInteger(codec,
1538                         MediaFormat.KEY_AAC_DRC_ALBUM_MODE);
1539                 assertEquals("DRC AlbumMode received from MediaCodec is not the Album Mode set"
1540                         + " runtime:" + runtimeChange, drcParams.mAlbumMode, albumModeFromCodec);
1541             }
1542             if (drcParams.mEffectType != 0) {
1543                 final int effectTypeFromCodec = DecoderTest.getOutputFormatInteger(codec,
1544                         MediaFormat.KEY_AAC_DRC_EFFECT_TYPE);
1545                 assertEquals("DRC Effect Type received from MediaCodec is not the Effect Type set"
1546                         + " runtime:" + runtimeChange, drcParams.mEffectType, effectTypeFromCodec);
1547             }
1548             if (drcParams.mDecoderTargetLevel != 0) {
1549                 final int targetLevelFromCodec = DecoderTest.getOutputFormatInteger(codec,
1550                         MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL);
1551                 assertEquals("DRC Target Ref Level received from MediaCodec is not the level set"
1552                         + " runtime:" + runtimeChange,
1553                         drcParams.mDecoderTargetLevel, targetLevelFromCodec);
1554             }
1555 
1556             final int cutFromCodec = DecoderTest.getOutputFormatInteger(codec,
1557                     MediaFormat.KEY_AAC_DRC_ATTENUATION_FACTOR);
1558             assertEquals("Attenuation factor received from MediaCodec differs from set:",
1559                     drcParams.mCut, cutFromCodec);
1560             final int boostFromCodec = DecoderTest.getOutputFormatInteger(codec,
1561                     MediaFormat.KEY_AAC_DRC_BOOST_FACTOR);
1562             assertEquals("Boost factor received from MediaCodec differs from set:",
1563                     drcParams.mBoost, boostFromCodec);
1564         }
1565 
1566         // expectedOutputLoudness == -2 indicates that output loudness is not tested
1567         if (expectedOutputLoudness != -2 && sIsAndroidRAndAbove) {
1568             final int outputLoudnessFromCodec = DecoderTest.getOutputFormatInteger(codec,
1569                     MediaFormat.KEY_AAC_DRC_OUTPUT_LOUDNESS);
1570             if (outputLoudnessFromCodec != expectedOutputLoudness) {
1571                 fail("Received decoder output loudness is not the expected value");
1572             }
1573         }
1574 
1575         codec.stop();
1576         codec.release();
1577         return decoded;
1578     }
1579 
1580     private short[] decodeToMemory(AudioParameter audioParams, int testinput,
1581             int eossample, List<Long> timestamps, DrcParams drcParams, String decoderName)
1582             throws IOException
1583     {
1584         final short[] decoded = decodeToMemory(audioParams, testinput, eossample, timestamps,
1585                 drcParams, decoderName, false, -2, false, 0, 0);
1586         return decoded;
1587     }
1588 
1589     private short[] decodeToMemory(AudioParameter audioParams, int testinput,
1590             int eossample, List<Long> timestamps, DrcParams drcParams, String decoderName,
1591             boolean runtimeChange)
1592         throws IOException
1593     {
1594         final short[] decoded = decodeToMemory(audioParams, testinput, eossample, timestamps,
1595                 drcParams, decoderName, runtimeChange, -2, false, 0, 0);
1596         return decoded;
1597     }
1598 
1599     private short[] decodeToMemory(AudioParameter audioParams, int testinput,
1600         int eossample, List<Long> timestamps, DrcParams drcParams, String decoderName,
1601         boolean runtimeChange, int expectedOutputLoudness)
1602         throws IOException
1603     {
1604         short [] decoded = decodeToMemory(audioParams, testinput, eossample, timestamps, drcParams,
1605                 decoderName, runtimeChange, expectedOutputLoudness, false, 0, 0);
1606         return decoded;
1607     }
1608 }
1609 
1610