SoundPool.java revision 1bc5c2645df96b22385f2cdb63a92576e388350e
1/* 2 * Copyright (C) 2007 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 17package android.media; 18 19import android.util.AndroidRuntimeException; 20import android.util.Log; 21import java.io.File; 22import java.io.FileDescriptor; 23import android.os.ParcelFileDescriptor; 24import java.lang.ref.WeakReference; 25import android.content.Context; 26import android.content.res.AssetFileDescriptor; 27import java.io.IOException; 28 29/** 30 * The SoundPool class manages and plays audio resources for applications. 31 * 32 * <p>A SoundPool is a collection of samples that can be loaded into memory 33 * from a resource inside the APK or from a file in the file system. The 34 * SoundPool library uses the MediaPlayer service to decode the audio 35 * into a raw 16-bit PCM mono or stereo stream. This allows applications 36 * to ship with compressed streams without having to suffer the CPU load 37 * and latency of decompressing during playback.</p> 38 * 39 * <p>In addition to low-latency playback, SoundPool can also manage the number 40 * of audio streams being rendered at once. When the SoundPool object is 41 * constructed, the maxStreams parameter sets the maximum number of streams 42 * that can be played at a time from this single SoundPool. SoundPool tracks 43 * the number of active streams. If the maximum number of streams is exceeded, 44 * SoundPool will automatically stop a previously playing stream based first 45 * on priority and then by age within that priority. Limiting the maximum 46 * number of streams helps to cap CPU loading and reducing the likelihood that 47 * audio mixing will impact visuals or UI performance.</p> 48 * 49 * <p>Sounds can be looped by setting a non-zero loop value. A value of -1 50 * causes the sound to loop forever. In this case, the application must 51 * explicitly call the stop() function to stop the sound. Any other non-zero 52 * value will cause the sound to repeat the specified number of times, e.g. 53 * a value of 3 causes the sound to play a total of 4 times.</p> 54 * 55 * <p>The playback rate can also be changed. A playback rate of 1.0 causes 56 * the sound to play at its original frequency (resampled, if necessary, 57 * to the hardware output frequency). A playback rate of 2.0 causes the 58 * sound to play at twice its original frequency, and a playback rate of 59 * 0.5 causes it to play at half its original frequency. The playback 60 * rate range is 0.5 to 2.0.</p> 61 * 62 * <p>Priority runs low to high, i.e. higher numbers are higher priority. 63 * Priority is used when a call to play() would cause the number of active 64 * streams to exceed the value established by the maxStreams parameter when 65 * the SoundPool was created. In this case, the stream allocator will stop 66 * the lowest priority stream. If there are multiple streams with the same 67 * low priority, it will choose the oldest stream to stop. In the case 68 * where the priority of the new stream is lower than all the active 69 * streams, the new sound will not play and the play() function will return 70 * a streamID of zero.</p> 71 * 72 * <p>Let's examine a typical use case: A game consists of several levels of 73 * play. For each level, there is a set of unique sounds that are used only 74 * by that level. In this case, the game logic should create a new SoundPool 75 * object when the first level is loaded. The level data itself might contain 76 * the list of sounds to be used by this level. The loading logic iterates 77 * through the list of sounds calling the appropriate SoundPool.load() 78 * function. This should typically be done early in the process to allow time 79 * for decompressing the audio to raw PCM format before they are needed for 80 * playback.</p> 81 * 82 * <p>Once the sounds are loaded and play has started, the application can 83 * trigger sounds by calling SoundPool.play(). Playing streams can be 84 * paused or resumed, and the application can also alter the pitch by 85 * adjusting the playback rate in real-time for doppler or synthesis 86 * effects.</p> 87 * 88 * <p>Note that since streams can be stopped due to resource constraints, the 89 * streamID is a reference to a particular instance of a stream. If the stream 90 * is stopped to allow a higher priority stream to play, the stream is no 91 * longer be valid. However, the application is allowed to call methods on 92 * the streamID without error. This may help simplify program logic since 93 * the application need not concern itself with the stream lifecycle.</p> 94 * 95 * <p>In our example, when the player has completed the level, the game 96 * logic should call SoundPool.release() to release all the native resources 97 * in use and then set the SoundPool reference to null. If the player starts 98 * another level, a new SoundPool is created, sounds are loaded, and play 99 * resumes.</p> 100 */ 101public class SoundPool 102{ 103 static { System.loadLibrary("soundpool"); } 104 105 private final static String TAG = "SoundPool"; 106 107 private int mNativeContext; // accessed by native methods 108 109 /** 110 * Constructor. Constructs a SoundPool object with the following 111 * characteristics: 112 * 113 * @param maxStreams the maximum number of simultaneous streams for this 114 * SoundPool object 115 * @param streamType the audio stream type as described in AudioManager 116 * For example, game applications will normally use 117 * {@link AudioManager#STREAM_MUSIC}. 118 * @param srcQuality the sample-rate converter quality. Currently has no 119 * effect. Use 0 for the default. 120 * @return a SoundPool object, or null if creation failed 121 */ 122 public SoundPool(int maxStreams, int streamType, int srcQuality) { 123 native_setup(new WeakReference<SoundPool>(this), maxStreams, streamType, srcQuality); 124 } 125 126 /** 127 * Load the sound from the specified path. 128 * 129 * @param path the path to the audio file 130 * @param priority the priority of the sound. Currently has no effect. Use 131 * a value of 1 for future compatibility. 132 * @return a sound ID. This value can be used to play or unload the sound. 133 */ 134 public int load(String path, int priority) 135 { 136 // pass network streams to player 137 if (path.startsWith("http:")) 138 return _load(path, priority); 139 140 // try local path 141 int id = 0; 142 try { 143 File f = new File(path); 144 if (f != null) { 145 ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); 146 if (fd != null) { 147 id = _load(fd.getFileDescriptor(), 0, f.length(), priority); 148 //Log.v(TAG, "close fd"); 149 fd.close(); 150 } 151 } 152 } catch (java.io.IOException e) {} 153 return id; 154 } 155 156 /** 157 * Load the sound from the specified APK resource. 158 * 159 * Note that the extension is dropped. For example, if you want to load 160 * a sound from the raw resource file "explosion.mp3", you would specify 161 * "R.raw.explosion" as the resource ID. Note that this means you cannot 162 * have both an "explosion.wav" and an "explosion.mp3" in the res/raw 163 * directory. 164 * 165 * @param context the application context 166 * @param resId the resource ID 167 * @param priority the priority of the sound. Currently has no effect. Use 168 * a value of 1 for future compatibility. 169 * @return a sound ID. This value can be used to play or unload the sound. 170 */ 171 public int load(Context context, int resId, int priority) { 172 AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId); 173 int id = 0; 174 if (afd != null) { 175 id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority); 176 try { 177 //Log.v(TAG, "close fd"); 178 afd.close(); 179 } catch (java.io.IOException ex) { 180 //Log.d(TAG, "close failed:", ex); 181 } 182 } 183 return id; 184 } 185 186 /** 187 * Load the sound from an asset file descriptor. 188 * 189 * @param afd an asset file descriptor 190 * @param priority the priority of the sound. Currently has no effect. Use 191 * a value of 1 for future compatibility. 192 * @return a sound ID. This value can be used to play or unload the sound. 193 */ 194 public int load(AssetFileDescriptor afd, int priority) { 195 if (afd != null) { 196 long len = afd.getLength(); 197 if (len < 0) { 198 throw new AndroidRuntimeException("no length for fd"); 199 } 200 return _load(afd.getFileDescriptor(), afd.getStartOffset(), len, priority); 201 } else { 202 return 0; 203 } 204 } 205 206 /** 207 * Load the sound from a FileDescriptor. 208 * 209 * This version is useful if you store multiple sounds in a single 210 * binary. The offset specifies the offset from the start of the file 211 * and the length specifies the length of the sound within the file. 212 * 213 * @param fd a FileDescriptor object 214 * @param offset offset to the start of the sound 215 * @param length length of the sound 216 * @param priority the priority of the sound. Currently has no effect. Use 217 * a value of 1 for future compatibility. 218 * @return a sound ID. This value can be used to play or unload the sound. 219 */ 220 public int load(FileDescriptor fd, long offset, long length, int priority) { 221 return _load(fd, offset, length, priority); 222 } 223 224 private native final int _load(String uri, int priority); 225 226 private native final int _load(FileDescriptor fd, long offset, long length, int priority); 227 228 /** 229 * Unload a sound from a sound ID. 230 * 231 * Unloads the sound specified by the soundID. This is the value 232 * returned by the load() function. Returns true if the sound is 233 * successfully unloaded, false if the sound was already unloaded. 234 * 235 * @param soundID a soundID returned by the load() function 236 * @return true if just unloaded, false if previously unloaded 237 */ 238 public native final boolean unload(int soundID); 239 240 /** 241 * Play a sound from a sound ID. 242 * 243 * Play the sound specified by the soundID. This is the value 244 * returned by the load() function. Returns a non-zero streamID 245 * if successful, zero if it fails. The streamID can be used to 246 * further control playback. Note that calling play() may cause 247 * another sound to stop playing if the maximum number of active 248 * streams is exceeded. A loop value of -1 means loop forever, 249 * a value of 0 means don't loop, other values indicate the 250 * number of repeats, e.g. a value of 1 plays the audio twice. 251 * The playback rate allows the application to vary the playback 252 * rate (pitch) of the sound. A value of 1.0 means play back at 253 * the original frequency. A value of 2.0 means play back twice 254 * as fast, and a value of 0.5 means playback at half speed. 255 * 256 * @param soundID a soundID returned by the load() function 257 * @param leftVolume left volume value (range = 0.0 to 1.0) 258 * @param rightVolume right volume value (range = 0.0 to 1.0) 259 * @param priority stream priority (0 = lowest priority) 260 * @param loop loop mode (0 = no loop, -1 = loop forever) 261 * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0) 262 * @return non-zero streamID if successful, zero if failed 263 */ 264 public native final int play(int soundID, float leftVolume, float rightVolume, 265 int priority, int loop, float rate); 266 267 /** 268 * Pause a playback stream. 269 * 270 * Pause the stream specified by the streamID. This is the 271 * value returned by the play() function. If the stream is 272 * playing, it will be paused. If the stream is not playing 273 * (e.g. is stopped or was previously paused), calling this 274 * function will have no effect. 275 * 276 * @param streamID a streamID returned by the play() function 277 */ 278 public native final void pause(int streamID); 279 280 /** 281 * Resume a playback stream. 282 * 283 * Resume the stream specified by the streamID. This 284 * is the value returned by the play() function. If the stream 285 * is paused, this will resume playback. If the stream was not 286 * previously paused, calling this function will have no effect. 287 * 288 * @param streamID a streamID returned by the play() function 289 */ 290 public native final void resume(int streamID); 291 292 /** 293 * Stop a playback stream. 294 * 295 * Stop the stream specified by the streamID. This 296 * is the value returned by the play() function. If the stream 297 * is playing, it will be stopped. It also releases any native 298 * resources associated with this stream. If the stream is not 299 * playing, it will have no effect. 300 * 301 * @param streamID a streamID returned by the play() function 302 */ 303 public native final void stop(int streamID); 304 305 /** 306 * Set stream volume. 307 * 308 * Sets the volume on the stream specified by the streamID. 309 * This is the value returned by the play() function. The 310 * value must be in the range of 0.0 to 1.0. If the stream does 311 * not exist, it will have no effect. 312 * 313 * @param streamID a streamID returned by the play() function 314 * @param leftVolume left volume value (range = 0.0 to 1.0) 315 * @param rightVolume right volume value (range = 0.0 to 1.0) 316 */ 317 public native final void setVolume(int streamID, 318 float leftVolume, float rightVolume); 319 320 /** 321 * Change stream priority. 322 * 323 * Change the priority of the stream specified by the streamID. 324 * This is the value returned by the play() function. Affects the 325 * order in which streams are re-used to play new sounds. If the 326 * stream does not exist, it will have no effect. 327 * 328 * @param streamID a streamID returned by the play() function 329 */ 330 public native final void setPriority(int streamID, int priority); 331 332 /** 333 * Set loop mode. 334 * 335 * Change the loop mode. A loop value of -1 means loop forever, 336 * a value of 0 means don't loop, other values indicate the 337 * number of repeats, e.g. a value of 1 plays the audio twice. 338 * If the stream does not exist, it will have no effect. 339 * 340 * @param streamID a streamID returned by the play() function 341 * @param loop loop mode (0 = no loop, -1 = loop forever) 342 */ 343 public native final void setLoop(int streamID, int loop); 344 345 /** 346 * Change playback rate. 347 * 348 * The playback rate allows the application to vary the playback 349 * rate (pitch) of the sound. A value of 1.0 means playback at 350 * the original frequency. A value of 2.0 means playback twice 351 * as fast, and a value of 0.5 means playback at half speed. 352 * If the stream does not exist, it will have no effect. 353 * 354 * @param streamID a streamID returned by the play() function 355 * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0) 356 */ 357 public native final void setRate(int streamID, float rate); 358 359 /** 360 * Release the SoundPool resources. 361 * 362 * Release all memory and native resources used by the SoundPool 363 * object. The SoundPool can no longer be used and the reference 364 * should be set to null. 365 */ 366 public native final void release(); 367 368 private native final void native_setup(Object mediaplayer_this, 369 int maxStreams, int streamType, int srcQuality); 370 371 protected void finalize() { release(); } 372} 373