Home | History | Annotate | Download | only in android
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      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 
     17 package com.badlogic.gdx.backends.android;
     18 
     19 import java.io.FileDescriptor;
     20 import java.io.IOException;
     21 import java.util.ArrayList;
     22 import java.util.List;
     23 
     24 import android.app.Activity;
     25 import android.content.Context;
     26 import android.content.res.AssetFileDescriptor;
     27 import android.media.AudioManager;
     28 import android.media.MediaPlayer;
     29 import android.media.SoundPool;
     30 
     31 import com.badlogic.gdx.Audio;
     32 import com.badlogic.gdx.Files.FileType;
     33 import com.badlogic.gdx.audio.AudioDevice;
     34 import com.badlogic.gdx.audio.AudioRecorder;
     35 import com.badlogic.gdx.audio.Music;
     36 import com.badlogic.gdx.audio.Sound;
     37 import com.badlogic.gdx.files.FileHandle;
     38 import com.badlogic.gdx.utils.GdxRuntimeException;
     39 
     40 /** An implementation of the {@link Audio} interface for Android.
     41  *
     42  * @author mzechner */
     43 public final class AndroidAudio implements Audio {
     44 	private final SoundPool soundPool;
     45 	private final AudioManager manager;
     46 	protected final List<AndroidMusic> musics = new ArrayList<AndroidMusic>();
     47 
     48 	public AndroidAudio (Context context, AndroidApplicationConfiguration config) {
     49 		if (!config.disableAudio) {
     50 			soundPool = new SoundPool(config.maxSimultaneousSounds, AudioManager.STREAM_MUSIC, 100);
     51 			manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
     52 			if (context instanceof Activity) {
     53 				((Activity)context).setVolumeControlStream(AudioManager.STREAM_MUSIC);
     54 			}
     55 		} else {
     56 			soundPool = null;
     57 			manager = null;
     58 		}
     59 	}
     60 
     61 	protected void pause () {
     62 		if (soundPool == null) {
     63 			return;
     64 		}
     65 		synchronized (musics) {
     66 			for (AndroidMusic music : musics) {
     67 				if (music.isPlaying()) {
     68 					music.pause();
     69 					music.wasPlaying = true;
     70 				} else
     71 					music.wasPlaying = false;
     72 			}
     73 		}
     74 		this.soundPool.autoPause();
     75 	}
     76 
     77 	protected void resume () {
     78 		if (soundPool == null) {
     79 			return;
     80 		}
     81 		synchronized (musics) {
     82 			for (int i = 0; i < musics.size(); i++) {
     83 				if (musics.get(i).wasPlaying) musics.get(i).play();
     84 			}
     85 		}
     86 		this.soundPool.autoResume();
     87 	}
     88 
     89 	/** {@inheritDoc} */
     90 	@Override
     91 	public AudioDevice newAudioDevice (int samplingRate, boolean isMono) {
     92 		if (soundPool == null) {
     93 			throw new GdxRuntimeException("Android audio is not enabled by the application config.");
     94 		}
     95 		return new AndroidAudioDevice(samplingRate, isMono);
     96 	}
     97 
     98 	/** {@inheritDoc} */
     99 	@Override
    100 	public Music newMusic (FileHandle file) {
    101 		if (soundPool == null) {
    102 			throw new GdxRuntimeException("Android audio is not enabled by the application config.");
    103 		}
    104 		AndroidFileHandle aHandle = (AndroidFileHandle)file;
    105 
    106 		MediaPlayer mediaPlayer = new MediaPlayer();
    107 
    108 		if (aHandle.type() == FileType.Internal) {
    109 			try {
    110 				AssetFileDescriptor descriptor = aHandle.getAssetFileDescriptor();
    111 				mediaPlayer.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
    112 				descriptor.close();
    113 				mediaPlayer.prepare();
    114 				AndroidMusic music = new AndroidMusic(this, mediaPlayer);
    115 				synchronized (musics) {
    116 					musics.add(music);
    117 				}
    118 				return music;
    119 			} catch (Exception ex) {
    120 				throw new GdxRuntimeException("Error loading audio file: " + file
    121 					+ "\nNote: Internal audio files must be placed in the assets directory.", ex);
    122 			}
    123 		} else {
    124 			try {
    125 				mediaPlayer.setDataSource(aHandle.file().getPath());
    126 				mediaPlayer.prepare();
    127 				AndroidMusic music = new AndroidMusic(this, mediaPlayer);
    128 				synchronized (musics) {
    129 					musics.add(music);
    130 				}
    131 				return music;
    132 			} catch (Exception ex) {
    133 				throw new GdxRuntimeException("Error loading audio file: " + file, ex);
    134 			}
    135 		}
    136 
    137 	}
    138 
    139 	/** Creates a new Music instance from the provided FileDescriptor. It is the caller's responsibility to close the file
    140 	 * descriptor. It is safe to do so as soon as this call returns.
    141 	 *
    142 	 * @param fd the FileDescriptor from which to create the Music
    143 	 *
    144 	 * @see Audio#newMusic(FileHandle)
    145 	 */
    146 	public Music newMusic (FileDescriptor fd) {
    147 		if (soundPool == null) {
    148 			throw new GdxRuntimeException("Android audio is not enabled by the application config.");
    149 		}
    150 
    151 		MediaPlayer mediaPlayer = new MediaPlayer();
    152 
    153 		try {
    154 			mediaPlayer.setDataSource(fd);
    155 			mediaPlayer.prepare();
    156 
    157 			AndroidMusic music = new AndroidMusic(this, mediaPlayer);
    158 			synchronized (musics) {
    159 				musics.add(music);
    160 			}
    161 			return music;
    162 		} catch (Exception ex) {
    163 			throw new GdxRuntimeException("Error loading audio from FileDescriptor", ex);
    164 		}
    165 	}
    166 
    167 	/** {@inheritDoc} */
    168 	@Override
    169 	public Sound newSound (FileHandle file) {
    170 		if (soundPool == null) {
    171 			throw new GdxRuntimeException("Android audio is not enabled by the application config.");
    172 		}
    173 		AndroidFileHandle aHandle = (AndroidFileHandle)file;
    174 		if (aHandle.type() == FileType.Internal) {
    175 			try {
    176 				AssetFileDescriptor descriptor = aHandle.getAssetFileDescriptor();
    177 				AndroidSound sound = new AndroidSound(soundPool, manager, soundPool.load(descriptor, 1));
    178 				descriptor.close();
    179 				return sound;
    180 			} catch (IOException ex) {
    181 				throw new GdxRuntimeException("Error loading audio file: " + file
    182 					+ "\nNote: Internal audio files must be placed in the assets directory.", ex);
    183 			}
    184 		} else {
    185 			try {
    186 				return new AndroidSound(soundPool, manager, soundPool.load(aHandle.file().getPath(), 1));
    187 			} catch (Exception ex) {
    188 				throw new GdxRuntimeException("Error loading audio file: " + file, ex);
    189 			}
    190 		}
    191 	}
    192 
    193 	/** {@inheritDoc} */
    194 	@Override
    195 	public AudioRecorder newAudioRecorder (int samplingRate, boolean isMono) {
    196 		if (soundPool == null) {
    197 			throw new GdxRuntimeException("Android audio is not enabled by the application config.");
    198 		}
    199 		return new AndroidAudioRecorder(samplingRate, isMono);
    200 	}
    201 
    202 	/** Kills the soundpool and all other resources */
    203 	public void dispose () {
    204 		if (soundPool == null) {
    205 			return;
    206 		}
    207 		synchronized (musics) {
    208 			// gah i hate myself.... music.dispose() removes the music from the list...
    209 			ArrayList<AndroidMusic> musicsCopy = new ArrayList<AndroidMusic>(musics);
    210 			for (AndroidMusic music : musicsCopy) {
    211 				music.dispose();
    212 			}
    213 		}
    214 		soundPool.release();
    215 	}
    216 }
    217