1.takePicture()を利用する場合
要は普通にカメラで撮影する場合。
ICSまで
takePicture()をコールするとシャッター音が必ず鳴るので特にコード上で意識することはない。
ICS以降
takePicture() に Camera.ShutterCallback を設定しないとシャッター音が鳴らない。
Camera.ShutterCallback の中身は空でよい。コードは以下のような感じ。
/** シャッターコールバックとピクチャコールバックの定義 */
private Camera.ShutterCallback mShutterListener =
new Camera.ShutterCallback() {
public void onShutter() {
// 空でOK。
}
};
private Camera.PictureCallback mPictureListener =
new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// ここは通常通り撮影時の処理をいろいろ記述。
}
};
/** 撮影 */
mCamera.takePicture(mShutterListener, null, mPictureListener);
なぜこのような仕様変更が発生したのかは謎。
よってどのOSバージョンでもシャッター音が鳴るようにするためには Camera.ShutterCallback を必ず記述すればよい。
2.takePicture()を利用しない場合
実際はプレビューキャプチャをしているが、撮影している風の演出をしたい場合など。シャッター音に限らず、端末のボリューム設定に関係なく音を鳴らしたいときに応用可能。
ただリフレクションを利用するため正攻法とはいえない。
音源を SoundPool を利用して音を鳴らす。このとき、Sound Pool コンストラクタの streamType 引数に特殊な値を設定してやる、というのが基本的な方針。
/** StremType の取得 */
int streamType = AudioManager.STREAM_SYSTEM; // ここは各アプリの方針に合わせて適切に設定
try {
Class asClass = Class.forName("android.media.AudioSystem");
Field sseField = asClass.getDeclaredField("STREAM_SYSTEM_ENFORCED");
streamType = sseField.getInt(null);
} catch (Exception e) {
// 例外処理
}
/** 読み込み */
SoundPool soundPool = new SoundPool(2, streamType, 0);
int soundID = soundPool.load(this, R.raw.shutter_sound, 1);
/** 再生 */
soundPool.play(soundID, 1.0f, 1.0f, 0, 0, 1.0f);
カメラアプリであればシャッターボタンを押したタイミングや ShutterCallback 内などで再生してやればよい。
Android のソースコードを読むと分かるが AudioSystem.java に STREAM_SYSTEM_ENFORCED という定数が定義してある。この値をアプリから強引に設定しようというのが上記サンプルのアプローチ。
/* @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
public static final int STREAM_SYSTEM_ENFORCED = 7;
STREAM_SYSTEM_ENFORCED は eclair からソースには入っており、端末メーカが故意に外さない限りは生きているであろう定数。@hide なパラメータだけに今後どうなるかは不明。