El Android multimedia framework inclou suport per executar una amplia diversitat de tipus de medis de forma que sigui fàcil d'integrar audio, video o imatges a les aplicacions Android.
Els fitxers de media es pode executar des de fitxers emmagatzemats en local que poden estar dins dels fitxers o recursos Android de la mateixa aplicació ( raw resources), de fitxers del sistema de fitxers local (p. ex. la memòria SSD) o d'streams de dades (Streaming). S'utilitzen les API MediaPlayer
NOTA: No és possible executar sons durant una trucada
MediaPlayer és la classe principal de l'API i permet executar tant audio com vídeo.
AudioManager This class manages audio sources and audio output on a device.
Al fitxer de manifest de l'aplicació (vegeu Manifest.xml) cal assignar els permisos correctes a l'aplicació:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
El control de l'execució de medis (aka playback) es controlat per una màquina d'estats. El següent diagrama mostra el cicle de vida i els estats de l'objecte MediaPlayer:
Les operacions que es poden realitzar són:
Els ovoides representen els estats. A les fletxes apareixen les operacions de playback que provoquen un transició d'estat. Les fletxes simples representen mètodes síncrons, en canvi els dobles representen mètodes asíncrons.
Els estats possibles són:
Un objecte de la classe MediaPlayer facilita l'execució d'audio i vídeo amb una configuració mínima.
És possible executar:
Podeu consultar una llista dels formats suportats a:
http://developer.android.com/guide/appendix/media-formats.html
Vegem un exemple:
MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1); mediaPlayer.start(); // no need to call prepare(); create() does that for you
L'exemple executa un audio d'un raw resource ( carpeta res/raw/):
Ara vegem un exemple de com utilitzar una URI:
Uri myUri = ....; // initialize Uri here MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(getApplicationContext(), myUri); mediaPlayer.prepare(); mediaPlayer.start();
O un exemple d'una URL remota:
String url = "http://........"; // your URL here MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(url); mediaPlayer.prepare(); // might take long! (for buffering, etc) mediaPlayer.start();
IMPORTANT: cal implementar les excepcions adients per controlar els errors en cas que el recurs a executar no existeixi (IllegalArgumentException i IOException )
Els MediaPlayer consumeixen recursos i els recursos són un valor important en aplicacions mòbils. Per aquesta raó quan ja no s'utilitza un MediaPLayer cal alliberar recursos amb el mètode:
release()
Per exemple, al mètode onStop() d'una activitat (a no ser que estiguem executant audio en segon terme, aleshores és recomana utilitzar un servei)
El codi per alliberar recursos és:
mediaPlayer.release(); mediaPlayer = null;
IMPORTANT: si no s'alliberen recursos a més poden succeir duplicacions quan l'activitat es torni a reprendre, per exemple al canviar entre landscape i portrait. Vegeu Handling Runtime Changes
És important assegurar-se que s'alliberen recursos per aquesta raó és una bona pràctica sobrescriure el mètode onDestroy() de les Actitivitats o Serveis Android:
public class MyService extends Service { MediaPlayer mMediaPlayer; // ... @Override public void onDestroy() { if (mMediaPlayer != null) mMediaPlayer.release(); } }
Sempre que es pugui cal mirar d'alliberar recursos sempre que es preveixi que durant un temps considerable no s'utilitzaran, per exemple al perdre el audio focus. En canvi si és poca estona més val la pena aturar l'execució una estona i reprendre-la.
Tal i com s'explica a Procesos Android, cal evitar executar operacions lentes des del UI thread. Per això caldria crear els objectes MediaPlayer des de un fil d'execució diferent. Com que aquest patró de disseny és molt habitual el sistema ja us proporciona el mètode:
prepareAsync()
Aquest mètode prepara els medis a executar i retorna immediatament mentrestant es fa la tasca per no penjar l'aplicació. Un cop el contingut està preparat, es crida el mètode
onPrepared()
del Listener
MediaPlayer.OnPreparedListener
que es configura amb el mètode:
setOnPreparedListener()
L'única manera d'executar un medi en segon terme (cosa que només sol tenir sentit en el cas d'àudio i no pas de vídeo, ja que en segon terme vol dir que no es veu el contingut de reproductor per pantalla però si que es sent l'audio) cal utilitzar un Servei Android i controlar l'execució des del servei.
Running asynchronously
First of all, like an Activity, all work in a Service is done in a single thread by default—in fact, if you're running an activity and a service from the same application, they use the same thread (the "main thread") by default. Therefore, services need to process incoming intents quickly and never perform lengthy computations when responding to them. If any heavy work or blocking calls are expected, you must do those tasks asynchronously: either from another thread you implement yourself, or using the framework's many facilities for asynchronous processing.
For instance, when using a MediaPlayer from your main thread, you should call prepareAsync() rather than prepare(), and implement a MediaPlayer.OnPreparedListener in order to be notified when the preparation is complete and you can start playing. For example:
public class MyService extends Service implements MediaPlayer.OnPreparedListener {
private static final ACTION_PLAY = "com.example.action.PLAY"; MediaPlayer mMediaPlayer = null;
public int onStartCommand(Intent intent, int flags, int startId) { ... if (intent.getAction().equals(ACTION_PLAY)) { mMediaPlayer = ... // initialize it here mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.prepareAsync(); // prepare async to not block main thread } }
/** Called when MediaPlayer is ready */ public void onPrepared(MediaPlayer player) { player.start(); }
}
On synchronous operations, errors would normally be signaled with an exception or an error code, but whenever you use asynchronous resources, you should make sure your application is notified of errors appropriately. In the case of a MediaPlayer, you can accomplish this by implementing a MediaPlayer.OnErrorListener and setting it in your MediaPlayer instance:
public class MyService extends Service implements MediaPlayer.OnErrorListener {
MediaPlayer mMediaPlayer;
public void initMediaPlayer() { // ...initialize the MediaPlayer here...
mMediaPlayer.setOnErrorListener(this); }
@Override public boolean onError(MediaPlayer mp, int what, int extra) { // ... react appropriately ... // The MediaPlayer has moved to the Error state, must be reset! }
}
It's important to remember that when an error occurs, the MediaPlayer moves to the Error state (see the documentation for the MediaPlayer class for the full state diagram) and you must reset it before you can use it again.
El Intent AUDIO_BECOMING_NOISY permet que s'aturi l'execució d'un audio quan l'usuari passa d'utilitzar els cascos a utilitzar els altaveus externs.
You can ensure your app stops playing music in these situations by handling the ACTION_AUDIO_BECOMING_NOISY intent, for which you can register a receiver by adding the following to your manifest:
Al fitxer de manifest:
<receiver android:name=".MusicIntentReceiver"> <intent-filter> <action android:name="android.media.AUDIO_BECOMING_NOISY" /> </intent-filter> </receiver>
Això registra la classe MusicIntentReceiver com a broadcast receiver per aquest tipus d'intent. Aleshores cal implementar la classe:
public class MusicIntentReceiver implements android.content.BroadcastReceiver { @Override public void onReceive(Context ctx, Intent intent) { if (intent.getAction().equals( android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) { // signal your service to stop playback // (via an Intent, for instance) } } }