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