SoundPool.java revision d282ac8610f72d964105efefe41120a5340f1ce0
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 Log.d(TAG, "error loading " + path); 154 } 155 return id; 156 } 157 158 /** 159 * Load the sound from the specified APK resource. 160 * 161 * Note that the extension is dropped. For example, if you want to load 162 * a sound from the raw resource file "explosion.mp3", you would specify 163 * "R.raw.explosion" as the resource ID. Note that this means you cannot 164 * have both an "explosion.wav" and an "explosion.mp3" in the res/raw 165 * directory. 166 * 167 * @param context the application context 168 * @param resId the resource ID 169 * @param priority the priority of the sound. Currently has no effect. Use 170 * a value of 1 for future compatibility. 171 * @return a sound ID. This value can be used to play or unload the sound. 172 */ 173 public int load(Context context, int resId, int priority) { 174 AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId); 175 int id = 0; 176 if (afd != null) { 177 id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority); 178 try { 179 //Log.v(TAG, "close fd"); 180 afd.close(); 181 } catch (java.io.IOException ex) { 182 //Log.d(TAG, "close failed:", ex); 183 } 184 } 185 return id; 186 } 187 188 /** 189 * Load the sound from an asset file descriptor. 190 * 191 * @param afd an asset file descriptor 192 * @param priority the priority of the sound. Currently has no effect. Use 193 * a value of 1 for future compatibility. 194 * @return a sound ID. This value can be used to play or unload the sound. 195 */ 196 public int load(AssetFileDescriptor afd, int priority) { 197 if (afd != null) { 198 long len = afd.getLength(); 199 if (len < 0) { 200 throw new AndroidRuntimeException("no length for fd"); 201 } 202 return _load(afd.getFileDescriptor(), afd.getStartOffset(), len, priority); 203 } else { 204 return 0; 205 } 206 } 207 208 /** 209 * Load the sound from a FileDescriptor. 210 * 211 * This version is useful if you store multiple sounds in a single 212 * binary. The offset specifies the offset from the start of the file 213 * and the length specifies the length of the sound within the file. 214 * 215 * @param fd a FileDescriptor object 216 * @param offset offset to the start of the sound 217 * @param length length of the sound 218 * @param priority the priority of the sound. Currently has no effect. Use 219 * a value of 1 for future compatibility. 220 * @return a sound ID. This value can be used to play or unload the sound. 221 */ 222 public int load(FileDescriptor fd, long offset, long length, int priority) { 223 return _load(fd, offset, length, priority); 224 } 225 226 private native final int _load(String uri, int priority); 227 228 private native final int _load(FileDescriptor fd, long offset, long length, int priority); 229 230 /** 231 * Unload a sound from a sound ID. 232 * 233 * Unloads the sound specified by the soundID. This is the value 234 * returned by the load() function. Returns true if the sound is 235 * successfully unloaded, false if the sound was already unloaded. 236 * 237 * @param soundID a soundID returned by the load() function 238 * @return true if just unloaded, false if previously unloaded 239 */ 240 public native final boolean unload(int soundID); 241 242 /** 243 * Play a sound from a sound ID. 244 * 245 * Play the sound specified by the soundID. This is the value 246 * returned by the load() function. Returns a non-zero streamID 247 * if successful, zero if it fails. The streamID can be used to 248 * further control playback. Note that calling play() may cause 249 * another sound to stop playing if the maximum number of active 250 * streams is exceeded. A loop value of -1 means loop forever, 251 * a value of 0 means don't loop, other values indicate the 252 * number of repeats, e.g. a value of 1 plays the audio twice. 253 * The playback rate allows the application to vary the playback 254 * rate (pitch) of the sound. A value of 1.0 means play back at 255 * the original frequency. A value of 2.0 means play back twice 256 * as fast, and a value of 0.5 means playback at half speed. 257 * 258 * @param soundID a soundID returned by the load() function 259 * @param leftVolume left volume value (range = 0.0 to 1.0) 260 * @param rightVolume right volume value (range = 0.0 to 1.0) 261 * @param priority stream priority (0 = lowest priority) 262 * @param loop loop mode (0 = no loop, -1 = loop forever) 263 * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0) 264 * @return non-zero streamID if successful, zero if failed 265 */ 266 public native final int play(int soundID, float leftVolume, float rightVolume, 267 int priority, int loop, float rate); 268 269 /** 270 * Pause a playback stream. 271 * 272 * Pause the stream specified by the streamID. This is the 273 * value returned by the play() function. If the stream is 274 * playing, it will be paused. If the stream is not playing 275 * (e.g. is stopped or was previously paused), calling this 276 * function will have no effect. 277 * 278 * @param streamID a streamID returned by the play() function 279 */ 280 public native final void pause(int streamID); 281 282 /** 283 * Resume a playback stream. 284 * 285 * Resume the stream specified by the streamID. This 286 * is the value returned by the play() function. If the stream 287 * is paused, this will resume playback. If the stream was not 288 * previously paused, calling this function will have no effect. 289 * 290 * @param streamID a streamID returned by the play() function 291 */ 292 public native final void resume(int streamID); 293 294 /** 295 * Stop a playback stream. 296 * 297 * Stop the stream specified by the streamID. This 298 * is the value returned by the play() function. If the stream 299 * is playing, it will be stopped. It also releases any native 300 * resources associated with this stream. If the stream is not 301 * playing, it will have no effect. 302 * 303 * @param streamID a streamID returned by the play() function 304 */ 305 public native final void stop(int streamID); 306 307 /** 308 * Set stream volume. 309 * 310 * Sets the volume on the stream specified by the streamID. 311 * This is the value returned by the play() function. The 312 * value must be in the range of 0.0 to 1.0. If the stream does 313 * not exist, it will have no effect. 314 * 315 * @param streamID a streamID returned by the play() function 316 * @param leftVolume left volume value (range = 0.0 to 1.0) 317 * @param rightVolume right volume value (range = 0.0 to 1.0) 318 */ 319 public native final void setVolume(int streamID, 320 float leftVolume, float rightVolume); 321 322 /** 323 * Change stream priority. 324 * 325 * Change the priority of the stream specified by the streamID. 326 * This is the value returned by the play() function. Affects the 327 * order in which streams are re-used to play new sounds. If the 328 * stream does not exist, it will have no effect. 329 * 330 * @param streamID a streamID returned by the play() function 331 */ 332 public native final void setPriority(int streamID, int priority); 333 334 /** 335 * Set loop mode. 336 * 337 * Change the loop mode. A loop value of -1 means loop forever, 338 * a value of 0 means don't loop, other values indicate the 339 * number of repeats, e.g. a value of 1 plays the audio twice. 340 * If the stream does not exist, it will have no effect. 341 * 342 * @param streamID a streamID returned by the play() function 343 * @param loop loop mode (0 = no loop, -1 = loop forever) 344 */ 345 public native final void setLoop(int streamID, int loop); 346 347 /** 348 * Change playback rate. 349 * 350 * The playback rate allows the application to vary the playback 351 * rate (pitch) of the sound. A value of 1.0 means playback at 352 * the original frequency. A value of 2.0 means playback twice 353 * as fast, and a value of 0.5 means playback at half speed. 354 * If the stream does not exist, it will have no effect. 355 * 356 * @param streamID a streamID returned by the play() function 357 * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0) 358 */ 359 public native final void setRate(int streamID, float rate); 360 361 /** 362 * Release the SoundPool resources. 363 * 364 * Release all memory and native resources used by the SoundPool 365 * object. The SoundPool can no longer be used and the reference 366 * should be set to null. 367 */ 368 public native final void release(); 369 370 private native final void native_setup(Object mediaplayer_this, 371 int maxStreams, int streamType, int srcQuality); 372 373 protected void finalize() { release(); } 374} 375