1 /*
2  * Copyright (C) 2015 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 com.android.cts.verifier.audio;
18 
19 import android.content.Context;
20 import android.media.AudioFormat;
21 import android.media.AudioManager;
22 import android.media.AudioTrack;
23 import android.media.MediaPlayer;
24 import android.net.Uri;
25 import android.net.rtp.AudioStream;
26 import android.util.Log;
27 
28 import com.android.cts.verifier.audio.wavelib.PipeShort;
29 
30 import java.io.IOException;
31 
32 public class SoundPlayerObject extends Thread {
33     private static final String LOGTAG = "SoundPlayerObject";
34     private MediaPlayer mMediaPlayer;
35     private boolean isInitialized = false;
36     private boolean isRunning = false;
37 
38     public PipeShort mPipe = new PipeShort(65536);
39     private short[] mAudioShortArray;
40 
41     public AudioTrack mAudioTrack;
42     public int mSamplingRate = 48000;
43     private int mChannelConfigOut = AudioFormat.CHANNEL_OUT_MONO;
44     private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
45     int mMinPlayBufferSizeInBytes = 0;
46     int mMinBufferSizeInSamples = 0;
47 
48     private int mStreamType = AudioManager.STREAM_MUSIC;
49     private int mResId = -1;
50     private boolean mUseMediaPlayer = true;
51     private float mBalance = 0.5f; //0 left, 1 right
52 
getCurrentResId()53     public int getCurrentResId() {
54         return mResId;
55     }
56 
getStreamType()57     public int getStreamType () {
58         return mStreamType;
59     }
60 
run()61     public void run() {
62         setPriority(Thread.MAX_PRIORITY);
63         isRunning = true;
64         while (isRunning) {
65 
66             if (!mUseMediaPlayer && isInitialized && isPlaying()) {
67                 int valuesAvailable = mPipe.availableToRead();
68                 if (valuesAvailable > 0) {
69 
70                     int valuesOfInterest = valuesAvailable;
71                     if (mMinBufferSizeInSamples < valuesOfInterest) {
72                         valuesOfInterest = mMinBufferSizeInSamples;
73                     }
74                     mPipe.read(mAudioShortArray, 0,valuesOfInterest);
75                     //inject into output.
76                     mAudioTrack.write(mAudioShortArray, 0, valuesOfInterest);
77                 }
78             } else {
79                 try {
80                     sleep(10);
81                 } catch (InterruptedException e) {
82                     e.printStackTrace();
83                 }
84             }
85         }
86     }
87 
setBalance(float balance)88     public void setBalance(float balance) {
89         mBalance = balance;
90         if (mUseMediaPlayer) {
91             if (mMediaPlayer != null) {
92                 float left = Math.min(2.0f * (1.0f - mBalance), 1.0f);
93                 float right = Math.min(2.0f * mBalance, 1.0f);
94                 mMediaPlayer.setVolume(left, right);
95                 log(String.format("Setting balance to %f", mBalance));
96             }
97         }
98     }
99 
setStreamType(int streamType)100     public void setStreamType(int streamType) {
101         mStreamType = streamType;
102     }
103 
rewind()104     public void rewind() {
105         if (mUseMediaPlayer) {
106             if (mMediaPlayer != null) {
107                 mMediaPlayer.seekTo(0);
108             }
109         }
110     }
111 
setSoundWithResId(Context context, int resId)112     public void setSoundWithResId(Context context, int resId) {
113         boolean playing = isPlaying();
114         //release player
115         releasePlayer();
116         mResId = resId;
117         if (mUseMediaPlayer) {
118             mMediaPlayer = new MediaPlayer();
119             try {
120                 log("opening resource with stream type: " + mStreamType);
121                 mMediaPlayer.setAudioStreamType(mStreamType);
122                 mMediaPlayer.setDataSource(context.getApplicationContext(),
123                         Uri.parse("android.resource://com.android.cts.verifier/" + resId));
124                 mMediaPlayer.prepare();
125             } catch (IOException e) {
126                 e.printStackTrace();
127             }
128             mMediaPlayer.setLooping(true);
129             setBalance(mBalance);
130         } else {
131             mMinPlayBufferSizeInBytes = AudioTrack.getMinBufferSize(mSamplingRate,
132                     mChannelConfigOut, mAudioFormat);
133 
134             mMinBufferSizeInSamples = mMinPlayBufferSizeInBytes / 2;
135             mAudioShortArray = new short[mMinBufferSizeInSamples * 4];
136 
137             mAudioTrack = new AudioTrack(mStreamType,
138                     mSamplingRate,
139                     mChannelConfigOut,
140                     mAudioFormat,
141                     mMinPlayBufferSizeInBytes,
142                     AudioTrack.MODE_STREAM /* FIXME runtime test for API level 9 ,
143                 mSessionId */);
144             mPipe.flush();
145             isInitialized = true;
146         }
147 
148         log("done preparing media player");
149         if (playing)
150             play(true); //start playing if it was playing before
151     }
152 
isPlaying()153     public boolean isPlaying() {
154         boolean result = false;
155         if (mUseMediaPlayer) {
156             if (mMediaPlayer != null) {
157                 result = mMediaPlayer.isPlaying();
158             }
159         } else {
160             if (mAudioTrack != null) {
161                 result = mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING;
162             }
163         }
164         return result;
165     }
166 
play(boolean play)167     public void play(boolean play) {
168         if (mUseMediaPlayer) {
169             if (mMediaPlayer != null) {
170                 if (play) {
171                     mMediaPlayer.start();
172                 } else {
173                     mMediaPlayer.pause();
174                 }
175             }
176         } else {
177             if (mAudioTrack != null && isInitialized) {
178                 if (play) {
179                     mPipe.flush();
180                     mAudioTrack.flush();
181                     mAudioTrack.play();
182                 } else {
183                     mAudioTrack.pause();
184                 }
185             }
186         }
187     }
188 
finish()189     public void finish() {
190         play(false);
191         releasePlayer();
192     }
193 
releasePlayer()194     private void releasePlayer() {
195         if (mMediaPlayer != null) {
196             mMediaPlayer.stop();
197             mMediaPlayer.release();
198             mMediaPlayer = null;
199         }
200 
201         if (mAudioTrack != null) {
202             mAudioTrack.stop();
203             mAudioTrack.release();
204             mAudioTrack = null;
205         }
206         isInitialized = false;
207     }
208 
209     /*
210        Misc
211     */
log(String msg)212     private static void log(String msg) {
213         Log.v(LOGTAG, msg);
214     }
215 }
216