diff options
| author | 2016-04-04 21:39:01 +0000 | |
|---|---|---|
| committer | 2016-04-04 21:39:02 +0000 | |
| commit | 2523d8f1e385bd69bfd33510f1041ee0b7e7db66 (patch) | |
| tree | b5314cb36f490503456c14c47c7a579c077d3b64 | |
| parent | 1e9c685d45100ccbf5879b2fd7df9c64e9da273a (diff) | |
| parent | d7a267de78771cfc68ce1a3ccef1f2c95f096db4 (diff) | |
Merge "MediaActionSound: fix SoundPool load race condition" into nyc-dev
| -rw-r--r-- | media/java/android/media/MediaActionSound.java | 141 |
1 files changed, 114 insertions, 27 deletions
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java index 1fee58707613..983ca754acd1 100644 --- a/media/java/android/media/MediaActionSound.java +++ b/media/java/android/media/MediaActionSound.java @@ -45,8 +45,7 @@ public class MediaActionSound { private static final int NUM_MEDIA_SOUND_STREAMS = 1; private SoundPool mSoundPool; - private int[] mSoundIds; - private int mSoundIdToPlay; + private SoundState[] mSounds; private static final String[] SOUND_FILES = { "/system/media/audio/ui/camera_click.ogg", @@ -88,22 +87,57 @@ public class MediaActionSound { */ public static final int STOP_VIDEO_RECORDING = 3; - private static final int SOUND_NOT_LOADED = -1; + /** + * States for SoundState. + * STATE_NOT_LOADED : sample not loaded + * STATE_LOADING : sample being loaded: waiting for load completion callback + * STATE_LOADING_PLAY_REQUESTED : sample being loaded and playback request received + * STATE_LOADED : sample loaded, ready for playback + */ + private static final int STATE_NOT_LOADED = 0; + private static final int STATE_LOADING = 1; + private static final int STATE_LOADING_PLAY_REQUESTED = 2; + private static final int STATE_LOADED = 3; + + private class SoundState { + public final int name; + public int id; + public int state; + public SoundState(int name) { + this.name = name; + id = 0; // 0 is an invalid sample ID. + state = STATE_NOT_LOADED; + } + } /** * Construct a new MediaActionSound instance. Only a single instance is * needed for playing any platform media action sound; you do not need a * separate instance for each sound type. */ public MediaActionSound() { - mSoundPool = new SoundPool(NUM_MEDIA_SOUND_STREAMS, - AudioManager.STREAM_SYSTEM_ENFORCED, 0); + mSoundPool = new SoundPool.Builder() + .setMaxStreams(NUM_MEDIA_SOUND_STREAMS) + .setAudioAttributes(new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) + .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build()) + .build(); mSoundPool.setOnLoadCompleteListener(mLoadCompleteListener); - mSoundIds = new int[SOUND_FILES.length]; - for (int i = 0; i < mSoundIds.length; i++) { - mSoundIds[i] = SOUND_NOT_LOADED; + mSounds = new SoundState[SOUND_FILES.length]; + for (int i = 0; i < mSounds.length; i++) { + mSounds[i] = new SoundState(i); } - mSoundIdToPlay = SOUND_NOT_LOADED; + } + + private int loadSound(SoundState sound) { + int id = mSoundPool.load(SOUND_FILES[sound.name], 1); + if (id > 0) { + sound.state = STATE_LOADING; + sound.id = id; + } + return id; } /** @@ -118,13 +152,22 @@ public class MediaActionSound { * @see #START_VIDEO_RECORDING * @see #STOP_VIDEO_RECORDING */ - public synchronized void load(int soundName) { + public void load(int soundName) { if (soundName < 0 || soundName >= SOUND_FILES.length) { throw new RuntimeException("Unknown sound requested: " + soundName); } - if (mSoundIds[soundName] == SOUND_NOT_LOADED) { - mSoundIds[soundName] = - mSoundPool.load(SOUND_FILES[soundName], 1); + SoundState sound = mSounds[soundName]; + synchronized (sound) { + switch (sound.state) { + case STATE_NOT_LOADED: + if (loadSound(sound) <= 0) { + Log.e(TAG, "load() error loading sound: " + soundName); + } + break; + default: + Log.e(TAG, "load() called in wrong state: " + sound + " for sound: "+ soundName); + break; + } } } @@ -159,16 +202,31 @@ public class MediaActionSound { * @see #START_VIDEO_RECORDING * @see #STOP_VIDEO_RECORDING */ - public synchronized void play(int soundName) { + public void play(int soundName) { if (soundName < 0 || soundName >= SOUND_FILES.length) { throw new RuntimeException("Unknown sound requested: " + soundName); } - if (mSoundIds[soundName] == SOUND_NOT_LOADED) { - mSoundIdToPlay = - mSoundPool.load(SOUND_FILES[soundName], 1); - mSoundIds[soundName] = mSoundIdToPlay; - } else { - mSoundPool.play(mSoundIds[soundName], 1.0f, 1.0f, 0, 0, 1.0f); + SoundState sound = mSounds[soundName]; + synchronized (sound) { + switch (sound.state) { + case STATE_NOT_LOADED: + loadSound(sound); + if (loadSound(sound) <= 0) { + Log.e(TAG, "play() error loading sound: " + soundName); + break; + } + // FALL THROUGH + + case STATE_LOADING: + sound.state = STATE_LOADING_PLAY_REQUESTED; + break; + case STATE_LOADED: + mSoundPool.play(sound.id, 1.0f, 1.0f, 0, 0, 1.0f); + break; + default: + Log.e(TAG, "play() called in wrong state: " + sound.state + " for sound: "+ soundName); + break; + } } } @@ -176,14 +234,37 @@ public class MediaActionSound { new SoundPool.OnLoadCompleteListener() { public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { - if (status == 0) { - if (mSoundIdToPlay == sampleId) { - soundPool.play(sampleId, 1.0f, 1.0f, 0, 0, 1.0f); - mSoundIdToPlay = SOUND_NOT_LOADED; + for (SoundState sound : mSounds) { + if (sound.id != sampleId) { + continue; } - } else { - Log.e(TAG, "Unable to load sound for playback (status: " + - status + ")"); + int playSoundId = 0; + synchronized (sound) { + if (status != 0) { + sound.state = STATE_NOT_LOADED; + sound.id = 0; + Log.e(TAG, "OnLoadCompleteListener() error: " + status + + " loading sound: "+ sound.name); + return; + } + switch (sound.state) { + case STATE_LOADING: + sound.state = STATE_LOADED; + break; + case STATE_LOADING_PLAY_REQUESTED: + playSoundId = sound.id; + sound.state = STATE_LOADED; + break; + default: + Log.e(TAG, "OnLoadCompleteListener() called in wrong state: " + + sound.state + " for sound: "+ sound.name); + break; + } + } + if (playSoundId != 0) { + soundPool.play(playSoundId, 1.0f, 1.0f, 0, 0, 1.0f); + } + break; } } }; @@ -195,6 +276,12 @@ public class MediaActionSound { */ public void release() { if (mSoundPool != null) { + for (SoundState sound : mSounds) { + synchronized (sound) { + sound.state = STATE_NOT_LOADED; + sound.id = 0; + } + } mSoundPool.release(); mSoundPool = null; } |