/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.SystemProperties; import android.util.Log; import java.io.IOException; /** * <p>Use this class to play an appropriate sound when implementing a custom * still or video recording mechanism through the preview callbacks.</p> * * <p>There is no need to play sounds when using {@link #android.hardware.Camera#takePicture} * or {@link android.media.MediaRecorder} for still images or video, * respectively, as these play their own sounds when needed.</p> * * @hide */ public class CameraSound { private static final String TAG = "CameraSound"; /** * The sound used by {@link android.hardware.Camera#takePicture} to * indicate still image capture. */ public static final int SHUTTER_CLICK = 0; /** * A sound to indicate that focusing has completed. Because deciding * when this occurs is application-dependent, this sound is not used by * any methods in the Camera class. */ public static final int FOCUS_COMPLETE = 1; /** * The sound used by {@link android.media.MediaRecorder#start} to * indicate the start of video recording. */ public static final int START_VIDEO_RECORDING = 2; /** * The sound used by {@link android.media.MediaRecorder#stop} to * indicate the end of video recording. */ public static final int STOP_VIDEO_RECORDING = 3; private static final int NUM_SOUNDS = 4; private CameraSoundPlayer[] mCameraSoundPlayers; public CameraSound() { } /** * <p>Play one of the predefined platform sounds for camera actions.</p> * * <p>Use this method to play a platform-specific sound for various camera * actions. The sound playing is done asynchronously, with the same behavior * and content as the sounds played by {@link #takePicture takePicture}, * {@link android.media.MediaRecorder#start MediaRecorder.start}, and * {@link android.media.MediaRecorder#stop MediaRecorder.stop}.</p> * * <p>Using this method makes it easy to match the default device sounds * when recording or capturing data through the preview callbacks.</p> * * @param soundId The type of sound to play, selected from SHUTTER_CLICK, * FOCUS_COMPLETE, START_VIDEO_RECORDING, or STOP_VIDEO_RECORDING. * @see android.hardware#takePicture * @see android.media.MediaRecorder * @see #SHUTTER_CLICK * @see #FOCUS_COMPLETE * @see #START_VIDEO_RECORDING * @see #STOP_VIDEO_RECORDING */ public void playSound(int soundId) { if (mCameraSoundPlayers == null) { mCameraSoundPlayers = new CameraSoundPlayer[NUM_SOUNDS]; } if (mCameraSoundPlayers[soundId] == null) { mCameraSoundPlayers[soundId] = new CameraSoundPlayer(soundId); } mCameraSoundPlayers[soundId].play(); } public void release() { if (mCameraSoundPlayers != null) { for (CameraSoundPlayer csp: mCameraSoundPlayers) { if (csp != null) { csp.release(); } } mCameraSoundPlayers = null; } } private static class CameraSoundPlayer implements Runnable { private int mSoundId; private MediaPlayer mPlayer; private Thread mThread; private boolean mExit; private int mPlayCount; private static final String mShutterSound = "/system/media/audio/ui/camera_click.ogg"; private static final String mFocusSound = "/system/media/audio/ui/camera_focus.ogg"; private static final String mVideoStartSound = "/system/media/audio/ui/VideoRecord.ogg"; private static final String mVideoStopSound = "/system/media/audio/ui/VideoRecord.ogg"; @Override public void run() { String soundFilePath; switch (mSoundId) { case SHUTTER_CLICK: soundFilePath = mShutterSound; break; case FOCUS_COMPLETE: soundFilePath = mFocusSound; break; case START_VIDEO_RECORDING: soundFilePath = mVideoStartSound; break; case STOP_VIDEO_RECORDING: soundFilePath = mVideoStopSound; break; default: Log.e(TAG, "Unknown sound " + mSoundId + " requested."); return; } mPlayer = new MediaPlayer(); try { mPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM_ENFORCED); mPlayer.setDataSource(soundFilePath); mPlayer.setLooping(false); mPlayer.prepare(); } catch(IOException e) { Log.e(TAG, "Error setting up sound " + mSoundId, e); return; } while(true) { try { synchronized (this) { while(true) { if (mExit) { return; } else if (mPlayCount <= 0) { wait(); } else { mPlayCount--; break; } } } mPlayer.start(); } catch (Exception e) { Log.e(TAG, "Error playing sound " + mSoundId, e); } } } public CameraSoundPlayer(int soundId) { mSoundId = soundId; } public void play() { if (mThread == null) { mThread = new Thread(this); mThread.start(); } synchronized (this) { mPlayCount++; notifyAll(); } } public void release() { if (mThread != null) { synchronized (this) { mExit = true; notifyAll(); } try { mThread.join(); } catch (InterruptedException e) { } mThread = null; } if (mPlayer != null) { mPlayer.release(); mPlayer = null; } } @Override protected void finalize() { release(); } } }