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