1 /*
2  * Copyright (C) 2010 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.cts;
18 
19 import android.media.cts.R;
20 
21 import android.content.res.AssetFileDescriptor;
22 import android.media.audiofx.AudioEffect;
23 import android.media.AudioFormat;
24 import android.media.AudioManager;
25 import android.media.AudioRecord;
26 import android.media.AudioTrack;
27 import android.media.audiofx.PresetReverb;
28 import android.media.audiofx.EnvironmentalReverb;
29 import android.media.audiofx.Equalizer;
30 import android.media.MediaPlayer;
31 import android.media.MediaRecorder;
32 
33 import android.os.Looper;
34 import android.test.AndroidTestCase;
35 import android.util.Log;
36 import java.util.UUID;
37 
38 public class AudioEffectTest extends PostProcTestBase {
39 
40     private String TAG = "AudioEffectTest";
41     private final static int MIN_NUMBER_EFFECTS = 1;
42     // allow +/- 5% tolerance between set and get delays
43     private final static float DELAY_TOLERANCE = 1.05f;
44     // allow +/- 5% tolerance between set and get ratios
45     private final static float RATIO_TOLERANCE = 1.05f;
46     // AudioRecord sampling rate
47     private final static int SAMPLING_RATE = 44100;
48 
49     private final static int MAX_LOOPER_WAIT_COUNT = 10;
50 
51     private AudioEffect mEffect = null;
52     private AudioEffect mEffect2 = null;
53     private MediaPlayer mMediaPlayer = null;
54     private int mError = 0;
55 
56     private ListenerThread mEffectListenerLooper = null;
57 
58     //-----------------------------------------------------------------
59     // AUDIOEFFECT TESTS:
60     //----------------------------------
61 
62     @Override
tearDown()63     protected void tearDown() throws Exception {
64         releaseEffect();
65         terminateMediaPlayerLooper();
66         terminateListenerLooper();
67     }
68 
69     //-----------------------------------------------------------------
70     // 0 - static methods
71     //----------------------------------
72 
73     //Test case 0.0: test queryEffects() and platfrom at least provides an Equalizer
test0_0QueryEffects()74     public void test0_0QueryEffects() throws Exception {
75 
76         AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
77 
78         assertTrue("test0_0QueryEffects: number of effects < MIN_NUMBER_EFFECTS: "+desc.length,
79                 (desc.length >= MIN_NUMBER_EFFECTS));
80 
81         boolean hasEQ = false;
82 
83         for (int i = 0; i < desc.length; i++) {
84             if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
85                 hasEQ = true;
86                 break;
87             }
88         }
89         assertTrue("test0_0QueryEffects: equalizer not found", hasEQ);
90     }
91 
92     //-----------------------------------------------------------------
93     // 1 - constructor
94     //----------------------------------
95 
getAudioRecord()96     private AudioRecord getAudioRecord() {
97         AudioRecord ar = null;
98         try {
99             ar = new AudioRecord(MediaRecorder.AudioSource.DEFAULT,
100                     SAMPLING_RATE,
101                     AudioFormat.CHANNEL_CONFIGURATION_MONO,
102                     AudioFormat.ENCODING_PCM_16BIT,
103                     AudioRecord.getMinBufferSize(SAMPLING_RATE,
104                             AudioFormat.CHANNEL_CONFIGURATION_MONO,
105                             AudioFormat.ENCODING_PCM_16BIT) * 10);
106             assertNotNull("Could not create AudioRecord", ar);
107             assertEquals("AudioRecord not initialized",
108                     AudioRecord.STATE_INITIALIZED, ar.getState());
109         } catch (IllegalArgumentException e) {
110             fail("AudioRecord invalid parameter");
111         }
112         return ar;
113     }
114 
115 //    // Test case 1.0: test constructor from effect type and get effect ID
116 //    public void test1_0ConstructorFromType() ...
117 //    Note: This test was removed because it used hidden api's.
118 
119 
120 //    //Test case 1.1: test constructor from effect uuid
121 //    public void test1_1ConstructorFromUuid() ...
122 //    Note: This test was removed because:
123 //     1. will fail in devices that offload effects
124 //     2. it used hidden api's.
125 
126 //    //Test case 1.2: test constructor failure from unknown type
127 //    public void test1_2ConstructorUnknownType() ...
128 //    Note: This test was removed because it used hidden api's.
129 
130     //Test case 1.3: test getEnabled() failure when called on released effect
test1_3GetEnabledAfterRelease()131     public void test1_3GetEnabledAfterRelease() throws Exception {
132         try {
133             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
134                     AudioEffect.EFFECT_TYPE_NULL,
135                     0,
136                     0);
137             assertNotNull("could not create AudioEffect", effect);
138             effect.release();
139             try {
140                 effect.getEnabled();
141                 fail("getEnabled() processed after release()");
142             } catch (IllegalStateException e) {
143 
144             }
145         } catch (IllegalArgumentException e) {
146             fail("AudioEffect not found");
147         } catch (UnsupportedOperationException e) {
148             fail("Effect library not loaded");
149         }
150     }
151 
152     //Test case 1.4: test contructor on mediaPlayer audio session
test1_4InsertOnMediaPlayer()153     public void test1_4InsertOnMediaPlayer() throws Exception {
154         MediaPlayer mp = new MediaPlayer();
155         assertNotNull("could not create mediaplayer", mp);
156         AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3);
157         mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
158         afd.close();
159         getEffect(AudioEffect.EFFECT_TYPE_EQUALIZER, mp.getAudioSessionId());
160         try {
161             mEffect.setEnabled(true);
162 
163         } catch (IllegalStateException e) {
164             fail("AudioEffect not initialized");
165         } finally {
166             mp.release();
167             releaseEffect();
168         }
169     }
170 
171     //Test case 1.5: test auxiliary effect attachement on MediaPlayer
test1_5AuxiliaryOnMediaPlayer()172     public void test1_5AuxiliaryOnMediaPlayer() throws Exception {
173         if (!isPresetReverbAvailable()) {
174             return;
175         }
176         synchronized(mLock) {
177             mInitialized = false;
178             createMediaPlayerLooper();
179             waitForLooperInitialization_l();
180 
181             mError = 0;
182             AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3);
183             mMediaPlayer.setDataSource(afd.getFileDescriptor(),
184                                        afd.getStartOffset(),
185                                        afd.getLength());
186             afd.close();
187             getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
188             try {
189                 try {
190                     mMediaPlayer.attachAuxEffect(mEffect.getId());
191                     mMediaPlayer.setAuxEffectSendLevel(1.0f);
192                     mLock.wait(1000);
193                 } catch(Exception e) {
194                     fail("Attach effect: wait was interrupted.");
195                 }
196                 assertTrue("error on attachAuxEffect", mError == 0);
197             } catch (IllegalStateException e) {
198                 fail("attach aux effect failed");
199             } finally {
200                 terminateMediaPlayerLooper();
201                 releaseEffect();
202             }
203         }
204     }
205 
206     //Test case 1.6: test auxiliary effect attachement failure before setDatasource
test1_6AuxiliaryOnMediaPlayerFailure()207     public void test1_6AuxiliaryOnMediaPlayerFailure() throws Exception {
208         if (!isPresetReverbAvailable()) {
209             return;
210         }
211         synchronized(mLock) {
212             mInitialized = false;
213             createMediaPlayerLooper();
214             waitForLooperInitialization_l();
215 
216             getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
217 
218             mError = 0;
219             int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
220             while (mError == 0 && (looperWaitCount-- > 0)) {
221                 try {
222                     try {
223                         mMediaPlayer.attachAuxEffect(mEffect.getId());
224                     } catch (IllegalStateException e) {
225                         terminateMediaPlayerLooper();
226                         releaseEffect();
227                         fail("attach aux effect failed");
228                     }
229                     mLock.wait();
230                 } catch(Exception e) {
231                 }
232             }
233             assertTrue("no error on attachAuxEffect", mError != 0);
234         }
235         terminateMediaPlayerLooper();
236         releaseEffect();
237     }
238 
239 
240     //Test case 1.7: test auxiliary effect attachement on AudioTrack
test1_7AuxiliaryOnAudioTrack()241     public void test1_7AuxiliaryOnAudioTrack() throws Exception {
242         if (!isPresetReverbAvailable()) {
243             return;
244         }
245         AudioTrack track = null;
246         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
247         try {
248             track = new AudioTrack(
249                                 AudioManager.STREAM_MUSIC,
250                                 44100,
251                                 AudioFormat.CHANNEL_OUT_MONO,
252                                 AudioFormat.ENCODING_PCM_16BIT,
253                                 AudioTrack.getMinBufferSize(44100,
254                                                             AudioFormat.CHANNEL_OUT_MONO,
255                                                             AudioFormat.ENCODING_PCM_16BIT),
256                                                             AudioTrack.MODE_STREAM);
257             assertNotNull("could not create AudioTrack", track);
258 
259             int status = track.attachAuxEffect(mEffect.getId());
260             if (status != AudioTrack.SUCCESS) {
261                 fail("could not attach aux effect");
262             }
263             status = track.setAuxEffectSendLevel(1.0f);
264             if (status != AudioTrack.SUCCESS) {
265                 fail("could not set send level");
266             }
267         } catch (IllegalStateException e) {
268             fail("could not attach aux effect");
269         } catch (IllegalArgumentException e) {
270             fail("could not create AudioTrack");
271         } finally {
272             if (track != null) {
273                 track.release();
274             }
275             releaseEffect();
276         }
277     }
278 
279     //-----------------------------------------------------------------
280     // 2 - enable/ disable
281     //----------------------------------
282 
283 
284     //Test case 2.0: test setEnabled() and getEnabled() in valid state
test2_0SetEnabledGetEnabled()285     public void test2_0SetEnabledGetEnabled() throws Exception {
286         try {
287             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
288                     AudioEffect.EFFECT_TYPE_NULL,
289                     0,
290                     0);
291             assertNotNull("could not create AudioEffect", effect);
292             try {
293                 effect.setEnabled(true);
294                 assertTrue("invalid state from getEnabled", effect.getEnabled());
295                 effect.setEnabled(false);
296                 assertFalse("invalid state to getEnabled", effect.getEnabled());
297 
298             } catch (IllegalStateException e) {
299                 fail("setEnabled() in wrong state");
300             } finally {
301                 effect.release();
302             }
303         } catch (IllegalArgumentException e) {
304             fail("AudioEffect not found");
305 
306         } catch (UnsupportedOperationException e) {
307             fail("Effect library not loaded");
308         }
309     }
310 
311     //Test case 2.1: test setEnabled() throws exception after release
test2_1SetEnabledAfterRelease()312     public void test2_1SetEnabledAfterRelease() throws Exception {
313         try {
314             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
315                     AudioEffect.EFFECT_TYPE_NULL,
316                     0,
317                     0);
318             assertNotNull("could not create AudioEffect", effect);
319             effect.release();
320             try {
321                 effect.setEnabled(true);
322                 fail("setEnabled() processed after release");
323             } catch (IllegalStateException e) {
324                 // test passed
325             }
326         } catch (IllegalArgumentException e) {
327             fail("AudioEffect not found");
328         } catch (UnsupportedOperationException e) {
329             fail("Effect library not loaded");
330         }
331     }
332 
333     //-----------------------------------------------------------------
334     // 3 - set/get parameters
335     //----------------------------------
336 
337     //Test case 3.0: test setParameter(byte[], byte[]) / getParameter(byte[], byte[])
test3_0SetParameterByteArrayByteArray()338     public void test3_0SetParameterByteArrayByteArray() throws Exception {
339         if (!isPresetReverbAvailable()) {
340             return;
341         }
342         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
343         try {
344             byte[] param = mEffect.intToByteArray(PresetReverb.PARAM_PRESET);
345             byte[] value = new byte[2];
346             int status = mEffect.getParameter(param, value);
347             assertFalse("getParameter 1 failed", AudioEffect.isError(status));
348             short preset = PresetReverb.PRESET_SMALLROOM;
349             if (mEffect.byteArrayToShort(value) == preset) {
350                 preset = PresetReverb.PRESET_MEDIUMROOM;
351             }
352             value = mEffect.shortToByteArray(preset);
353             status = mEffect.setParameter(param, value);
354             assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
355             status = mEffect.getParameter(param, value);
356             assertFalse("getParameter 2 failed", AudioEffect.isError(status));
357             assertEquals("get/set Parameter failed", preset,
358                     mEffect.byteArrayToShort(value));
359 
360         } catch (IllegalArgumentException e) {
361             fail("Bad parameter value");
362         } catch (UnsupportedOperationException e) {
363             fail("setParameter() rejected");
364         } catch (IllegalStateException e) {
365             fail("setParameter() called in wrong state");
366         } finally {
367             releaseEffect();
368         }
369     }
370 
371     //Test case 3.1: test setParameter(int, int) / getParameter(int, int[])
test3_1SetParameterIntInt()372     public void test3_1SetParameterIntInt() throws Exception {
373         if (!isEnvReverbAvailable()) {
374             return;
375         }
376         getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
377         try {
378             int param = EnvironmentalReverb.PARAM_DECAY_TIME;
379             int[] value = new int[1];
380             int status = mEffect.getParameter(param, value);
381             assertFalse("getParameter 1 failed", AudioEffect.isError(status));
382             int time = 500;
383             if (value[0] == time) {
384                 time = 1000;
385             }
386             status = mEffect.setParameter(param, time);
387             assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
388             status = mEffect.getParameter(param, value);
389             assertFalse("getParameter 2 failed", AudioEffect.isError(status));
390             assertTrue("got incorrect decay time",
391                     ((float)value[0] > (float)(time / DELAY_TOLERANCE)) &&
392                     ((float)value[0] < (float)(time * DELAY_TOLERANCE)));
393 
394         } catch (IllegalArgumentException e) {
395             fail("Bad parameter value");
396         } catch (UnsupportedOperationException e) {
397             fail("setParameter() rejected");
398         } catch (IllegalStateException e) {
399             fail("setParameter() called in wrong state");
400         } finally {
401             releaseEffect();
402         }
403     }
404 
405     //Test case 3.2: test setParameter(int, short) / getParameter(int, short[])
test3_2SetParameterIntShort()406     public void test3_2SetParameterIntShort() throws Exception {
407         if (!isPresetReverbAvailable()) {
408             return;
409         }
410         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
411         try {
412             int param = PresetReverb.PARAM_PRESET;
413             short[] value = new short[1];
414             int status = mEffect.getParameter(param, value);
415             assertFalse("getParameter 1 failed", AudioEffect.isError(status));
416             short preset = PresetReverb.PRESET_SMALLROOM;
417             if (value[0] == preset) {
418                 preset = PresetReverb.PRESET_MEDIUMROOM;
419             }
420             status = mEffect.setParameter(param, preset);
421             assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
422             status = mEffect.getParameter(param, value);
423             assertFalse("getParameter 2 failed", AudioEffect.isError(status));
424             assertEquals("get/set Parameter failed", preset, value[0]);
425 
426         } catch (IllegalArgumentException e) {
427             fail("Bad parameter value");
428         } catch (UnsupportedOperationException e) {
429             fail("setParameter() rejected");
430         } catch (IllegalStateException e) {
431             fail("setParameter() called in wrong state");
432         } finally {
433             releaseEffect();
434         }
435     }
436 
437     //Test case 3.3: test setParameter(int, byte[]) / getParameter(int, byte[])
test3_3SetParameterIntByteArray()438     public void test3_3SetParameterIntByteArray() throws Exception {
439         if (!isEnvReverbAvailable()) {
440             return;
441         }
442         getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
443         try {
444             int param = EnvironmentalReverb.PARAM_DECAY_TIME;
445             byte[] value = new byte[4];
446             int status = mEffect.getParameter(param, value);
447             assertFalse("getParameter 1 failed", AudioEffect.isError(status));
448             int time = 500;
449             if (mEffect.byteArrayToInt(value) == time) {
450                 time = 1000;
451             }
452             value = mEffect.intToByteArray(time);
453             status = mEffect.setParameter(param, value);
454             assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
455             status = mEffect.getParameter(param, value);
456             assertFalse("getParameter 2 failed", AudioEffect.isError(status));
457             int time2 = mEffect.byteArrayToInt(value);
458             assertTrue("got incorrect decay time",
459                     ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
460                     ((float)time2 < (float)(time * DELAY_TOLERANCE)));
461 
462         } catch (IllegalArgumentException e) {
463             fail("Bad parameter value");
464         } catch (UnsupportedOperationException e) {
465             fail("setParameter() rejected");
466         } catch (IllegalStateException e) {
467             fail("setParameter() called in wrong state");
468         } finally {
469             releaseEffect();
470         }
471     }
472 
473     //Test case 3.4: test setParameter(int[], int[]) / getParameter(int[], int[])
test3_4SetParameterIntArrayIntArray()474     public void test3_4SetParameterIntArrayIntArray() throws Exception {
475         if (!isEnvReverbAvailable()) {
476             return;
477         }
478         getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
479         try {
480             int[] param = new int[1];
481             int[] value = new int[1];
482             param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
483             int status = mEffect.getParameter(param, value);
484             assertFalse("getParameter 1 failed", AudioEffect.isError(status));
485             int[] time = new int[1];
486             time[0] = 500;
487             if (value[0] == time[0]) {
488                 time[0] = 1000;
489             }
490             status = mEffect.setParameter(param, time);
491             assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
492             status = mEffect.getParameter(param, value);
493             assertFalse("getParameter 2 failed", AudioEffect.isError(status));
494             assertTrue("got incorrect decay time",
495                     ((float)value[0] > (float)(time[0] / DELAY_TOLERANCE)) &&
496                     ((float)value[0] < (float)(time[0] * DELAY_TOLERANCE)));
497 
498         } catch (IllegalArgumentException e) {
499             fail("Bad parameter value");
500         } catch (UnsupportedOperationException e) {
501             fail("setParameter() rejected");
502         } catch (IllegalStateException e) {
503             fail("setParameter() called in wrong state");
504         } finally {
505             releaseEffect();
506         }
507     }
508 
509     //Test case 3.5: test setParameter(int[], short[]) / getParameter(int[], short[])
510 
test3_5SetParameterIntArrayShortArray()511     public void test3_5SetParameterIntArrayShortArray() throws Exception {
512         if (!isPresetReverbAvailable()) {
513             return;
514         }
515         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
516         try {
517             int[] param = new int[1];
518             param[0] = PresetReverb.PARAM_PRESET;
519             short[] value = new short[1];
520             int status = mEffect.getParameter(param, value);
521             assertFalse("getParameter 1 failed", AudioEffect.isError(status));
522             short[] preset = new short[1];
523             preset[0] = PresetReverb.PRESET_SMALLROOM;
524             if (value[0] == preset[0]) {
525                 preset[0] = PresetReverb.PRESET_MEDIUMROOM;
526             }
527             status = mEffect.setParameter(param, preset);
528             assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
529             status = mEffect.getParameter(param, value);
530             assertFalse("getParameter 2 failed", AudioEffect.isError(status));
531             assertEquals("get/set Parameter failed", preset[0], value[0]);
532 
533         } catch (IllegalArgumentException e) {
534             fail("Bad parameter value");
535         } catch (UnsupportedOperationException e) {
536             fail("setParameter() rejected");
537         } catch (IllegalStateException e) {
538             fail("setParameter() called in wrong state");
539         } finally {
540             releaseEffect();
541         }
542     }
543 
544     //Test case 3.6: test setParameter(int[], byte[]) / getParameter(int[], byte[])
test3_6SetParameterIntArrayByteArray()545     public void test3_6SetParameterIntArrayByteArray() throws Exception {
546         if (!isEnvReverbAvailable()) {
547             return;
548         }
549         getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
550         try {
551             int[] param = new int[1];
552             param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
553             byte[] value = new byte[4];
554             int status = mEffect.getParameter(param, value);
555             assertFalse("getParameter 1 failed", AudioEffect.isError(status));
556             int time = 500;
557             if (mEffect.byteArrayToInt(value) == time) {
558                 time = 1000;
559             }
560 
561             status = mEffect.setParameter(param, mEffect.intToByteArray(time));
562             assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
563             status = mEffect.getParameter(param, value);
564             assertFalse("getParameter 2 failed", AudioEffect.isError(status));
565             int time2 = mEffect.byteArrayToInt(value);
566             assertTrue("got incorrect decay time",
567                     ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
568                     ((float)time2 < (float)(time * DELAY_TOLERANCE)));
569 
570         } catch (IllegalArgumentException e) {
571             fail("Bad parameter value");
572         } catch (UnsupportedOperationException e) {
573             fail("setParameter() rejected");
574         } catch (IllegalStateException e) {
575             fail("setParameter() called in wrong state");
576         } finally {
577             releaseEffect();
578         }
579     }
580 
581     //Test case 3.7: test setParameter() throws exception after release()
test3_7SetParameterAfterRelease()582     public void test3_7SetParameterAfterRelease() throws Exception {
583         if (!isPresetReverbAvailable()) {
584             return;
585         }
586         AudioEffect effect = null;
587         try {
588             effect = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
589                                     AudioEffect.EFFECT_TYPE_NULL,
590                                     0,
591                                     0);
592             assertNotNull("could not create AudioEffect", effect);
593             effect.release();
594             effect.setParameter(PresetReverb.PARAM_PRESET, PresetReverb.PRESET_SMALLROOM);
595             fail("setParameter() processed after release");
596         } catch (IllegalArgumentException e) {
597             fail("Bad parameter value");
598         } catch (UnsupportedOperationException e) {
599             fail("setParameter() rejected");
600         } catch (IllegalStateException e) {
601             // test passed
602         } finally {
603             if (effect != null) {
604                 effect.release();
605             }
606         }
607     }
608 
609     //Test case 3.8: test getParameter() throws exception after release()
test3_8GetParameterAfterRelease()610     public void test3_8GetParameterAfterRelease() throws Exception {
611         if (!isPresetReverbAvailable()) {
612             return;
613         }
614         AudioEffect effect = null;
615         try {
616             effect = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
617                                     AudioEffect.EFFECT_TYPE_NULL,
618                                     0,
619                                     0);
620             assertNotNull("could not create AudioEffect", effect);
621             effect.release();
622             short[] value = new short[1];
623             effect.getParameter(PresetReverb.PARAM_PRESET, value);
624             fail("getParameter() processed after release");
625         } catch (IllegalArgumentException e) {
626             fail("Bad parameter value");
627         } catch (UnsupportedOperationException e) {
628             fail("getParameter() rejected");
629         } catch (IllegalStateException e) {
630             // test passed
631         } finally {
632             if (effect != null) {
633                 effect.release();
634             }
635         }
636     }
637 
638     //-----------------------------------------------------------------
639     // 4 priority and listeners
640     //----------------------------------
641 
642     //Test case 4.0: test control passed to higher priority client
test4_0setEnabledLowerPriority()643     public void test4_0setEnabledLowerPriority() throws Exception {
644         AudioEffect effect1 = null;
645         AudioEffect effect2 = null;
646         try {
647             effect1 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
648                                     AudioEffect.EFFECT_TYPE_NULL,
649                                     0,
650                                     0);
651             effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
652                     AudioEffect.EFFECT_TYPE_NULL,
653                     1,
654                     0);
655 
656             assertNotNull("could not create AudioEffect", effect1);
657             assertNotNull("could not create AudioEffect", effect2);
658 
659             assertTrue("Effect2 does not have control", effect2.hasControl());
660             assertFalse("Effect1 has control", effect1.hasControl());
661             assertTrue("Effect1 can enable",
662                     effect1.setEnabled(true) == AudioEffect.ERROR_INVALID_OPERATION);
663             assertFalse("Effect1 has enabled", effect2.getEnabled());
664 
665         } catch (IllegalArgumentException e) {
666             fail("Effect not found");
667         } catch (UnsupportedOperationException e) {
668             fail("Effect library not loaded");
669         } finally {
670             if (effect1 != null) {
671                 effect1.release();
672             }
673             if (effect2 != null) {
674                 effect2.release();
675             }
676         }
677     }
678 
679     //Test case 4.1: test control passed to higher priority client
test4_1setParameterLowerPriority()680     public void test4_1setParameterLowerPriority() throws Exception {
681         if (!isPresetReverbAvailable()) {
682             return;
683         }
684         AudioEffect effect1 = null;
685         AudioEffect effect2 = null;
686         try {
687             effect1 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
688                                     AudioEffect.EFFECT_TYPE_NULL,
689                                     0,
690                                     0);
691             effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
692                     AudioEffect.EFFECT_TYPE_NULL,
693                     1,
694                     0);
695 
696             assertNotNull("could not create AudioEffect", effect1);
697             assertNotNull("could not create AudioEffect", effect2);
698 
699             int status = effect2.setParameter(PresetReverb.PARAM_PRESET,
700                     PresetReverb.PRESET_SMALLROOM);
701             assertEquals("Effect2 setParameter failed",
702                     AudioEffect.SUCCESS, status);
703 
704             status = effect1.setParameter(PresetReverb.PARAM_PRESET,
705                     PresetReverb.PRESET_MEDIUMROOM);
706             assertEquals("Effect1 setParameter did not fail",
707                     AudioEffect.ERROR_INVALID_OPERATION, status);
708 
709             short[] value = new short[1];
710             status = effect2.getParameter(PresetReverb.PARAM_PRESET, value);
711             assertFalse("Effect2 getParameter failed",
712                     AudioEffect.isError(status));
713             assertEquals("Effect1 changed parameter", PresetReverb.PRESET_SMALLROOM
714                     , value[0]);
715 
716 
717         } catch (IllegalArgumentException e) {
718             fail("Effect not found");
719         } catch (UnsupportedOperationException e) {
720             fail("Effect library not loaded");
721         } finally {
722             if (effect1 != null) {
723                 effect1.release();
724             }
725             if (effect2 != null) {
726                 effect2.release();
727             }
728         }
729     }
730 
731     //Test case 4.2: test control status listener
test4_2ControlStatusListener()732     public void test4_2ControlStatusListener() throws Exception {
733         if (!isPresetReverbAvailable()) {
734             return;
735         }
736         synchronized(mLock) {
737             mHasControl = true;
738             mInitialized = false;
739             createListenerLooper(true, false, false);
740             waitForLooperInitialization_l();
741 
742             getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
743             int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
744             while (mHasControl && (looperWaitCount-- > 0)) {
745                 try {
746                     mLock.wait();
747                 } catch(Exception e) {
748                 }
749             }
750             terminateListenerLooper();
751             releaseEffect();
752         }
753         assertFalse("effect control not lost by effect1", mHasControl);
754     }
755 
756     //Test case 4.3: test enable status listener
test4_3EnableStatusListener()757     public void test4_3EnableStatusListener() throws Exception {
758         if (!isPresetReverbAvailable()) {
759             return;
760         }
761         synchronized(mLock) {
762             mInitialized = false;
763             createListenerLooper(false, true, false);
764             waitForLooperInitialization_l();
765 
766             mEffect2.setEnabled(true);
767             mIsEnabled = true;
768 
769             getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
770             assertTrue("effect not enabled", mEffect.getEnabled());
771             int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
772             while (mIsEnabled && (looperWaitCount-- > 0)) {
773                 try {
774                     mEffect.setEnabled(false);
775                     mLock.wait();
776                 } catch(Exception e) {
777                 }
778             }
779             terminateListenerLooper();
780             releaseEffect();
781         }
782         assertFalse("enable status not updated", mIsEnabled);
783     }
784 
785     //Test case 4.4: test parameter changed listener
test4_4ParameterChangedListener()786     public void test4_4ParameterChangedListener() throws Exception {
787         if (!isPresetReverbAvailable()) {
788             return;
789         }
790         synchronized(mLock) {
791             mInitialized = false;
792             createListenerLooper(false, false, true);
793             waitForLooperInitialization_l();
794             int status = mEffect2.setParameter(PresetReverb.PARAM_PRESET,
795                     PresetReverb.PRESET_SMALLROOM);
796             assertEquals("mEffect2 setParameter failed",
797                     AudioEffect.SUCCESS, status);
798             getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
799             mChangedParameter = -1;
800             mEffect.setParameter(PresetReverb.PARAM_PRESET,
801                     PresetReverb.PRESET_MEDIUMROOM);
802             int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
803             while (mChangedParameter == -1 && (looperWaitCount-- > 0)) {
804                 try {
805                     mLock.wait();
806                 } catch(Exception e) {
807                 }
808             }
809             terminateListenerLooper();
810             releaseEffect();
811         }
812         assertEquals("parameter change not received",
813                 PresetReverb.PARAM_PRESET, mChangedParameter);
814     }
815 
816     //-----------------------------------------------------------------
817     // 5 command method
818     //----------------------------------
819 
820 
821     //Test case 5.0: test command method
test5_0Command()822     public void test5_0Command() throws Exception {
823         if (!isPresetReverbAvailable()) {
824             return;
825         }
826         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
827         try {
828             byte[] cmd = new byte[0];
829             byte[] reply = new byte[4];
830             // command 3 is ENABLE
831             int status = mEffect.command(3, cmd, reply);
832             assertFalse("command failed", AudioEffect.isError(status));
833             assertTrue("effect not enabled", mEffect.getEnabled());
834 
835         } catch (IllegalStateException e) {
836             fail("command in illegal state");
837         } finally {
838             releaseEffect();
839         }
840     }
841 
842 
843     //-----------------------------------------------------------------
844     // private methods
845     //----------------------------------
846 
getEffect(UUID type, int session)847     private void getEffect(UUID type, int session) {
848          if (mEffect == null || session != mSession) {
849              if (session != mSession && mEffect != null) {
850                  mEffect.release();
851                  mEffect = null;
852              }
853              try {
854                  mEffect = new AudioEffect(type,
855                                              AudioEffect.EFFECT_TYPE_NULL,
856                                              0,
857                                              session);
858                  mSession = session;
859             } catch (IllegalArgumentException e) {
860                 Log.e(TAG, "getEffect() AudioEffect not found exception: "+e);
861             } catch (UnsupportedOperationException e) {
862                 Log.e(TAG, "getEffect() Effect library not loaded exception: "+e);
863             }
864          }
865          assertNotNull("could not create mEffect", mEffect);
866     }
867 
releaseEffect()868     private void releaseEffect() {
869         if (mEffect != null) {
870             mEffect.release();
871             mEffect = null;
872         }
873     }
874 
waitForLooperInitialization_l()875     private void waitForLooperInitialization_l() {
876         int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
877         while (!mInitialized && (looperWaitCount-- > 0)) {
878             try {
879                 mLock.wait();
880             } catch(Exception e) {
881             }
882         }
883         assertTrue(mInitialized);
884     }
885 
886     // Initializes the equalizer listener looper
887     class ListenerThread extends Thread {
888         boolean mControl;
889         boolean mEnable;
890         boolean mParameter;
891 
ListenerThread(boolean control, boolean enable, boolean parameter)892         public ListenerThread(boolean control, boolean enable, boolean parameter) {
893             super();
894             mControl = control;
895             mEnable = enable;
896             mParameter = parameter;
897         }
898 
cleanUp()899         public void cleanUp() {
900             if (mEffect2 != null) {
901                 mEffect2.setControlStatusListener(null);
902                 mEffect2.setEnableStatusListener(null);
903                 mEffect2.setParameterListener(null);
904             }
905         }
906     }
907 
createListenerLooper(boolean control, boolean enable, boolean parameter)908     private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
909         mEffectListenerLooper = new ListenerThread(control, enable, parameter) {
910             @Override
911             public void run() {
912                 // Set up a looper
913                 Looper.prepare();
914 
915                 // Save the looper so that we can terminate this thread
916                 // after we are done with it.
917                 mLooper = Looper.myLooper();
918 
919                 mEffect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
920                         AudioEffect.EFFECT_TYPE_NULL,
921                         0,
922                         0);
923                 assertNotNull("could not create Equalizer2", mEffect2);
924 
925                 synchronized(mLock) {
926                     if (mControl) {
927                         mEffect2.setControlStatusListener(
928                                 new AudioEffect.OnControlStatusChangeListener() {
929                             public void onControlStatusChange(
930                                     AudioEffect effect, boolean controlGranted) {
931                                 synchronized(mLock) {
932                                     if (effect == mEffect2) {
933                                         mHasControl = controlGranted;
934                                         mLock.notify();
935                                     }
936                                 }
937                             }
938                         });
939                     }
940                     if (mEnable) {
941                         mEffect2.setEnableStatusListener(
942                                 new AudioEffect.OnEnableStatusChangeListener() {
943                             public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
944                                 synchronized(mLock) {
945                                     if (effect == mEffect2) {
946                                         mIsEnabled = enabled;
947                                         mLock.notify();
948                                     }
949                                 }
950                             }
951                         });
952                     }
953                     if (mParameter) {
954                         mEffect2.setParameterListener(new AudioEffect.OnParameterChangeListener() {
955                             public void onParameterChange(AudioEffect effect, int status, byte[] param,
956                                     byte[] value)
957                             {
958                                 synchronized(mLock) {
959                                     if (effect == mEffect2) {
960                                         mChangedParameter = mEffect2.byteArrayToInt(param);
961                                         mLock.notify();
962                                     }
963                                 }
964                             }
965                         });
966                     }
967                     mInitialized = true;
968                     mLock.notify();
969                 }
970                 Looper.loop();  // Blocks forever until Looper.quit() is called.
971             }
972         };
973         mEffectListenerLooper.start();
974     }
975 
976     // Terminates the listener looper thread.
terminateListenerLooper()977     private void terminateListenerLooper() {
978         if (mEffectListenerLooper != null) {
979             mEffectListenerLooper.cleanUp();
980             if (mLooper != null) {
981                 mLooper.quit();
982                 mLooper = null;
983             }
984             try {
985                 mEffectListenerLooper.join();
986             } catch(InterruptedException e) {
987             }
988             mEffectListenerLooper = null;
989         }
990         if (mEffect2 != null) {
991             mEffect2.release();
992             mEffect2 = null;
993         }
994     }
995 
996     /*
997      * Initializes the message looper so that the MediaPlayer object can
998      * receive the callback messages.
999      */
createMediaPlayerLooper()1000     private void createMediaPlayerLooper() {
1001         new Thread() {
1002             @Override
1003             public void run() {
1004                 // Set up a looper to be used by mMediaPlayer.
1005                 Looper.prepare();
1006 
1007                 // Save the looper so that we can terminate this thread
1008                 // after we are done with it.
1009                 mLooper = Looper.myLooper();
1010 
1011                 mMediaPlayer = new MediaPlayer();
1012 
1013                 synchronized(mLock) {
1014                     mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
1015                         public boolean onError(MediaPlayer player, int what, int extra) {
1016                             synchronized(mLock) {
1017                                 mError = what;
1018                                 mLock.notify();
1019                             }
1020                             return true;
1021                         }
1022                     });
1023                     mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
1024                         public void onCompletion(MediaPlayer player) {
1025                             synchronized(mLock) {
1026                                 mLock.notify();
1027                             }
1028                         }
1029                     });
1030                     mInitialized = true;
1031                     mLock.notify();
1032                 }
1033                 Looper.loop();  // Blocks forever until Looper.quit() is called.
1034             }
1035         }.start();
1036     }
1037     /*
1038      * Terminates the message looper thread.
1039      */
terminateMediaPlayerLooper()1040     private void terminateMediaPlayerLooper() {
1041         if (mLooper != null) {
1042             mLooper.quit();
1043             mLooper = null;
1044         }
1045         if (mMediaPlayer != null) {
1046             mMediaPlayer.release();
1047         }
1048     }
1049 
1050 }
1051