1e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala/*
2e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * Copyright (C) 2012 The Android Open Source Project
3e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala *
4e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License");
5e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * you may not use this file except in compliance with the License.
6e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * You may obtain a copy of the License at
7e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala *
8e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala *      http://www.apache.org/licenses/LICENSE-2.0
9e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala *
10e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * Unless required by applicable law or agreed to in writing, software
11e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS,
12e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * See the License for the specific language governing permissions and
14e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * limitations under the License.
15e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala */
16e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
17e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvalapackage android.media;
18e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
19e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvalaimport android.media.AudioManager;
20e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvalaimport android.media.SoundPool;
21e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvalaimport android.util.Log;
22e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
23e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala/**
24e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * <p>A class for producing sounds that match those produced by various actions
25e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * taken by the media and camera APIs.  </p>
26e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala *
27e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * <p>Use this class to play an appropriate camera operation sound when
28e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * implementing a custom still or video recording mechanism (through the Camera
29e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * preview callbacks with {@link android.hardware.Camera#setPreviewCallback
30e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * Camera.setPreviewCallback}, or through GPU processing with {@link
31e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * android.hardware.Camera#setPreviewTexture Camera.setPreviewTexture}, for
32e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * example), or when implementing some other camera-like function in your
33e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * application.</p>
34e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala *
35e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * <p>There is no need to play sounds when using
36e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * {@link android.hardware.Camera#takePicture Camera.takePicture} or
37e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * {@link android.media.MediaRecorder} for still images or video, respectively,
38e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * as the Android framework will play the appropriate sounds when needed for
39e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala * these calls.</p>
40e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala *
41e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala */
42e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvalapublic class MediaActionSound {
43e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    private static final int NUM_MEDIA_SOUND_STREAMS = 1;
44e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
45e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    private SoundPool mSoundPool;
46e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    private int[]     mSoundIds;
47e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    private int       mSoundIdToPlay;
48e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
49e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    private static final String[] SOUND_FILES = {
50e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        "/system/media/audio/ui/camera_click.ogg",
51e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        "/system/media/audio/ui/camera_focus.ogg",
52e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        "/system/media/audio/ui/VideoRecord.ogg",
53e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        "/system/media/audio/ui/VideoRecord.ogg"
54e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    };
55e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
56e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    private static final String TAG = "MediaActionSound";
57e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    /**
58e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * The sound used by
59e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * {@link android.hardware.Camera#takePicture Camera.takePicture} to
60e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * indicate still image capture.
61e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #play
62e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     */
63e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    public static final int SHUTTER_CLICK         = 0;
64e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
65e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    /**
66e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * A sound to indicate that focusing has completed. Because deciding
67e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * when this occurs is application-dependent, this sound is not used by
68e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * any methods in the media or camera APIs.
69e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #play
70e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     */
71e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    public static final int FOCUS_COMPLETE        = 1;
72e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
73e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    /**
74e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * The sound used by
75e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * {@link android.media.MediaRecorder#start MediaRecorder.start()} to
76e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * indicate the start of video recording.
77e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #play
78e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     */
79e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    public static final int START_VIDEO_RECORDING = 2;
80e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
81e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    /**
82e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * The sound used by
83e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * {@link android.media.MediaRecorder#stop MediaRecorder.stop()} to
84e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * indicate the end of video recording.
85e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #play
86e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     */
87e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    public static final int STOP_VIDEO_RECORDING  = 3;
88e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
89e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    private static final int SOUND_NOT_LOADED = -1;
90e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
91e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    /**
92e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * Construct a new MediaActionSound instance. Only a single instance is
93e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * needed for playing any platform media action sound; you do not need a
94e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * separate instance for each sound type.
95e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     */
96e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    public MediaActionSound() {
97e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        mSoundPool = new SoundPool(NUM_MEDIA_SOUND_STREAMS,
98e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                AudioManager.STREAM_SYSTEM_ENFORCED, 0);
99e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        mSoundPool.setOnLoadCompleteListener(mLoadCompleteListener);
100e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        mSoundIds = new int[SOUND_FILES.length];
101e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        for (int i = 0; i < mSoundIds.length; i++) {
102e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            mSoundIds[i] = SOUND_NOT_LOADED;
103e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        }
104e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        mSoundIdToPlay = SOUND_NOT_LOADED;
105e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    }
106e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
107e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    /**
108e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * Preload a predefined platform sound to minimize latency when the sound is
109e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * played later by {@link #play}.
110e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @param soundName The type of sound to preload, selected from
111e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     *         SHUTTER_CLICK, FOCUS_COMPLETE, START_VIDEO_RECORDING, or
112e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     *         STOP_VIDEO_RECORDING.
113e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #play
114e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #SHUTTER_CLICK
115e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #FOCUS_COMPLETE
116e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #START_VIDEO_RECORDING
117e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #STOP_VIDEO_RECORDING
118e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     */
119e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    public synchronized void load(int soundName) {
120e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        if (soundName < 0 || soundName >= SOUND_FILES.length) {
121e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            throw new RuntimeException("Unknown sound requested: " + soundName);
122e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        }
123e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
124e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            mSoundIds[soundName] =
125e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                    mSoundPool.load(SOUND_FILES[soundName], 1);
126e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        }
127e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    }
128e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
129e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    /**
130e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * <p>Play one of the predefined platform sounds for media actions.</p>
131e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     *
132e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * <p>Use this method to play a platform-specific sound for various media
133e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * actions. The sound playback is done asynchronously, with the same
134e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * behavior and content as the sounds played by
135e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * {@link android.hardware.Camera#takePicture Camera.takePicture},
136e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * {@link android.media.MediaRecorder#start MediaRecorder.start}, and
137e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * {@link android.media.MediaRecorder#stop MediaRecorder.stop}.</p>
138e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     *
139e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * <p>Using this method makes it easy to match the default device sounds
140e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * when recording or capturing data through the preview callbacks, or when
141e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * implementing custom camera-like features in your
142e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * application.</p>
143e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     *
144e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * <p>If the sound has not been loaded by {@link #load} before calling play,
145e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * play will load the sound at the cost of some additional latency before
146e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * sound playback begins. </p>
147e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     *
148e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @param soundName The type of sound to play, selected from
149e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     *         SHUTTER_CLICK, FOCUS_COMPLETE, START_VIDEO_RECORDING, or
150e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     *         STOP_VIDEO_RECORDING.
151e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see android.hardware.Camera#takePicture
152e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see android.media.MediaRecorder
153e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #SHUTTER_CLICK
154e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #FOCUS_COMPLETE
155e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #START_VIDEO_RECORDING
156e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     * @see #STOP_VIDEO_RECORDING
157e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     */
158e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    public synchronized void play(int soundName) {
159e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        if (soundName < 0 || soundName >= SOUND_FILES.length) {
160e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            throw new RuntimeException("Unknown sound requested: " + soundName);
161e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        }
162e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
163e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            mSoundIdToPlay =
164e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                    mSoundPool.load(SOUND_FILES[soundName], 1);
165e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            mSoundIds[soundName] = mSoundIdToPlay;
166e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        } else {
167e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            mSoundPool.play(mSoundIds[soundName], 1.0f, 1.0f, 0, 0, 1.0f);
168e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        }
169e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    }
170e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
171e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    private SoundPool.OnLoadCompleteListener mLoadCompleteListener =
172e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            new SoundPool.OnLoadCompleteListener() {
173e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        public void onLoadComplete(SoundPool soundPool,
174e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                int sampleId, int status) {
175e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            if (status == 0) {
176e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                if (mSoundIdToPlay == sampleId) {
177e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                    soundPool.play(sampleId, 1.0f, 1.0f, 0, 0, 1.0f);
178e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                    mSoundIdToPlay = SOUND_NOT_LOADED;
179e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                }
180e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            } else {
181e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                Log.e(TAG, "Unable to load sound for playback (status: " +
182e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala                        status + ")");
183e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala            }
184e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala        }
185e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    };
186e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala
187e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    /**
188a4fd93751d2dd29febfc3022319e7f250fd6b732Eino-Ville Talvala     * Free up all audio resources used by this MediaActionSound instance. Do
189a4fd93751d2dd29febfc3022319e7f250fd6b732Eino-Ville Talvala     * not call any other methods on a MediaActionSound instance after calling
190a4fd93751d2dd29febfc3022319e7f250fd6b732Eino-Ville Talvala     * release().
191e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala     */
192e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    public void release() {
193a4fd93751d2dd29febfc3022319e7f250fd6b732Eino-Ville Talvala        if (mSoundPool != null) {
194a4fd93751d2dd29febfc3022319e7f250fd6b732Eino-Ville Talvala            mSoundPool.release();
195a4fd93751d2dd29febfc3022319e7f250fd6b732Eino-Ville Talvala            mSoundPool = null;
196a4fd93751d2dd29febfc3022319e7f250fd6b732Eino-Ville Talvala        }
197e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala    }
198e69095869c1b324aa20991ed1805c492c3f731e8Eino-Ville Talvala}
199