reproductor - Android MediaPlayer funciona bien en la aplicación de transmisión de audio personalizada hasta Android 2.1, pero no en versiones superiores
reproductor de musica para android codigo fuente (3)
La clase StreamingMediaPlayer
está utilizando una técnica de doble búfer para evitar las limitaciones en versiones anteriores a la versión 1.2 de Android. Todas las versiones de producción del sistema operativo Android incluyen un MediaPlayer que admite medios de transmisión (1). Recomendaría hacerlo en lugar de utilizar esta técnica de doble buffer para resolver el problema.
Android OS 2.2 reemplazó el antiguo código del reproductor multimedia con el reproductor FrightCast, que probablemente esté actuando de manera diferente en este caso.
Los números de línea en su rastro de pila no se asignan al archivo al que se vincula, así que supongo que hay una versión diferente que está usando en realidad. Voy a adivinar que MediaPlayer
está informando sobre NullPointerException
pero ni FileInputStream
ni el FileDescriptor
devuelto pueden ser null
.
(1) Antes de la versión 2.2, el reproductor multimedia no reconocería las transmisiones de ShoutCast con un encabezado de versión "ICY / 1.1" en la respuesta. Al crear un proxy que reemplace esto con "HTTP / 1.1" puede resolverlo. Vea la clase StreamProxy aquí para un ejemplo.
EDITAR:
Android 2.2 MediaPlayer funciona bien con una URL SHOUTcast pero no con la otra
Necesito reproducir archivos de audio desde URLs externas (transmisión shoutcast). Actualmente, los archivos de audio se descargan de manera incremental y se reproducen tan pronto como recibimos suficiente audio en el almacenamiento temporal local del teléfono. Estoy usando la clase StreamingMediaPlayer .
Verifique este fragmento de código:
private MediaPlayer createMediaPlayer(File mediaFile)
throws IOException {
MediaPlayer mPlayer = new MediaPlayer();
//example of mediaFile =/data/data/package/cache/playingMedia0.dat
FileInputStream fis = new FileInputStream(mediaFile);
mPlayer.setDataSource(fis.getFD());
mPlayer.prepare();
return mPlayer;
}
Estado actual:
1- Funciona bien desde Android 1.6 a 2.1, pero no en las versiones superiores como Android 2.2.
2- El "mPlayer.setDataSource (fis.getFD ())" es la línea que arroja el error.
3- El error es "No se puede crear el reproductor de medios"
Otra solución probada:
Intenté a continuación la solución alternativa, pero nada funcionó hasta ahora.
Android 2.2 MediaPlayer funciona bien con una URL SHOUTcast pero no con la otra
¿Qué estoy buscando?
Mi objetivo es tener una paz de código que pueda funcionar en Android 2.1 y versiones posteriores.
Este problema también se discute aquí:
1- Comportamiento de Media Player Inconsistente 2.2
2- Código de Android para la transmisión de secuencias de shoutcast se rompe en 2.2
3- Este tema también se discute en muchas preguntas en este sitio, pero encontré la respuesta en ningún lugar.
4- markmail.org
Traza de LogCat:
Unable to to create media player
Error copying buffered conent.
java.lang.NullPointerException
com.ms.iradio.StreamingMediaPlayer.startMediaPlayer(StreamingMediaPlayer.java:251)
com.ms.iradio.StreamingMediaPlayer.access$2(StreamingMediaPlayer.java:221)
com.ms.iradio.StreamingMediaPlayer$2.run(StreamingMediaPlayer.java:204)
android.os.Handler.handleCallback(Handler.java:587)
android.os.Handler.dispatchMessage(Handler.java:92)
android.os.Looper.loop(Looper.java:123)
android.app.ActivityThread.main(ActivityThread.java:3683)
java.lang.reflect.Method.invokeNative(Native Method)
java.lang.reflect.Method.invoke(Method.java:507)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
dalvik.system.NativeStart.main(Native Method)
El problema es que la transmisión de tipo de contenido "audio / aacp" no es compatible directamente. Algunas bibliotecas de decodificación se pueden usar para jugar "aacp", por favor vea la solución a continuación:
Freeware Advanced Audio (AAC) Decoder para Android
Considere problemas legales mientras lo usa .
[E] l proyecto http://code.google.com/p/aacplayer-android/ tiene licencia bajo GPL, por lo que puede crear aplicaciones comerciales además de eso, pero debe completar la GPL, principalmente significa publicar tu código también Si usa el segundo proyecto http://code.google.com/p/aacdecoder-android/ , no necesita publicar su código (la biblioteca tiene licencia bajo LGPL).
Estoy usando este código y ejecuto 2.2 a la versión superior para la transmisión descargada.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
public class StreamingMediaPlayer {
private static final int INTIAL_KB_BUFFER = 96*10;//assume 96kbps*10secs/8bits per byte
private TextView textStreamed;
private ImageButton playButton;
private ProgressBar progressBar;
ProgressBar pb;
int audiofiletime=0;
private long mediaLengthInSeconds;
private int totalKbRead = 0;
int totalsize=0;
int numread;
int totalBytesRead = 0;
private final Handler handler = new Handler();
private MediaPlayer mediaPlayer;
private File downloadingMediaFile;
private boolean isInterrupted;
private Context context;
private int counter = 0;
public StreamingMediaPlayer(Context context,TextView textStreamed, ImageButton playButton, Button streamButton,ProgressBar progressBar,ProgressBar pb)
{
this.context = context;
this.textStreamed = textStreamed;
this.playButton = playButton;
this.progressBar = progressBar;
this.pb=pb;
}
/**
* Progressivly download the media to a temporary location and update the MediaPlayer as new content becomes available.
*/
public void startStreaming(final String mediaUrl) throws IOException {
//this.mediaLengthInSeconds = 100;
Runnable r = new Runnable() {
public void run() {
try {
downloadAudioIncrement(mediaUrl);
} catch (IOException e) {
Log.e(getClass().getName(), "Unable to initialize the MediaPlayer for fileUrl=" + mediaUrl, e);
return;
}
}
};
new Thread(r).start();
}
/**
* Download the url stream to a temporary location and then call the setDataSource
* for that local file
*/
@SuppressWarnings({ "resource", "unused" })
public void downloadAudioIncrement(String mediaUrl) throws IOException {
URLConnection cn = new URL(mediaUrl).openConnection();
cn.connect();
InputStream stream = cn.getInputStream();
if (stream == null) {
Log.e(getClass().getName(), "Unable to create InputStream for mediaUrl:" + mediaUrl);
}
///////////////////save sdcard///////////////
File direct = new File(Environment.getExternalStorageDirectory()+"/punya");
if(!direct.exists()) {
if(direct.mkdir()); //directory is created;
}
String[] files=mediaUrl.split("/");
String fileName=files[files.length-1];
fileName = fileName.replace(".m4a", ".rdo");
//create a new file, to save the downloaded file
File file = new File(direct,fileName);
@SuppressWarnings("resource")
FileOutputStream fileOutput = new FileOutputStream(file);
///////////////////end/////////////////
totalsize=cn.getContentLength();
//mediaLengthInKb = 10000;
downloadingMediaFile = new File(context.getCacheDir(),fileName);
if (downloadingMediaFile.exists()) {
downloadingMediaFile.delete();
}
FileOutputStream out = new FileOutputStream(downloadingMediaFile);
byte buf[] = new byte[16384];
int incrementalBytesRead = 0;
do {
numread = stream.read(buf);
if (numread <= 0)
break;
out.write(buf, 0, numread);
fileOutput.write(buf, 0, numread);
totalBytesRead += numread;
incrementalBytesRead += numread;
totalKbRead = totalBytesRead/1000;
// pb.setMax(100);
// pb.setProgress(totalKbRead);
testMediaBuffer();
fireDataLoadUpdate();
} while (validateNotInterrupted());
stream.close();
if (validateNotInterrupted()) {
fireDataFullyLoaded();
}
}
private boolean validateNotInterrupted() {
if (isInterrupted) {
if (mediaPlayer != null) {
mediaPlayer.pause();
//mediaPlayer.release();
}
return false;
} else {
return true;
}
}
/**
* Test whether we need to transfer buffered data to the MediaPlayer.
* Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler.
*/
private void testMediaBuffer() {
Runnable updater = new Runnable() {
public void run() {
if (mediaPlayer == null) {
// Only create the MediaPlayer once we have the minimum buffered data
if ( totalKbRead >= INTIAL_KB_BUFFER) {
try {
startMediaPlayer();
} catch (Exception e) {
Log.e(getClass().getName(), "Error copying buffered conent.", e);
}
}
} else if ( mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000 ){
// NOTE: The media player has stopped at the end so transfer any existing buffered data
// We test for < 1second of data because the media player can stop when there is still
// a few milliseconds of data left to play
transferBufferToMediaPlayer();
}
}
};
handler.post(updater);
}
private void startMediaPlayer() {
try {
//File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".m4a");
//moveFile(downloadingMediaFile,bufferedFile);
// Log.e(getClass().getName(),"Buffered File path: " + bufferedFile.getAbsolutePath());
// Log.e(getClass().getName(),"Buffered File length: " + bufferedFile.length()+"");
mediaPlayer = createMediaPlayer(downloadingMediaFile);
//mediaPlayer.start();
startPlayProgressUpdater();
//playButton.setEnabled(true);
playButton.setVisibility(View.VISIBLE);
} catch (IOException e) {
Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e);
return;
}
}
private MediaPlayer createMediaPlayer(File mediaFile)
throws IOException {
MediaPlayer mPlayer = new MediaPlayer();
mPlayer.setOnErrorListener(
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(getClass().getName(), "Error in MediaPlayer: (" + what +") with extra (" +extra +")" );
return false;
}
});
FileInputStream fis = new FileInputStream(mediaFile);
mPlayer.setDataSource(fis.getFD());
mPlayer.prepare();
return mPlayer;
}
/**
* Transfer buffered data to the MediaPlayer.
* NOTE: Interacting with a MediaPlayer on a non-main UI thread can cause thread-lock and crashes so
* this method should always be called using a Handler.
*/
private void transferBufferToMediaPlayer() {
try {
boolean wasPlaying = mediaPlayer.isPlaying();
int curPosition = mediaPlayer.getCurrentPosition();
File oldBufferedFile = new File(context.getCacheDir(),"playingMedia" + counter + ".m4a");
File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".m4a");
bufferedFile.deleteOnExit();
moveFile(downloadingMediaFile,bufferedFile);
//mediaPlayer.pause();
mediaPlayer.release();
mediaPlayer = createMediaPlayer(bufferedFile);
mediaPlayer.seekTo(curPosition);
boolean atEndOfFile = mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000;
if (wasPlaying || atEndOfFile){
mediaPlayer.start();
}
oldBufferedFile.delete();
}catch (Exception e) {
Log.e(getClass().getName(), "Error updating to newly loaded content.", e);
}
}
private void fireDataLoadUpdate() {
Runnable updater = new Runnable() {
public void run() {
//float loadProgress = ((float)totalBytesRead/(float)mediaLengthInKb);
//float per = ((float)numread/mediaLengthInKb) * 100;
float per = ((float)totalBytesRead/totalsize) * 100;
textStreamed.setText((totalKbRead + " Kb (" + (int)per + "%)"));
progressBar.setSecondaryProgress((int)(per));
pb.setSecondaryProgress((int)(per));
}
};
handler.post(updater);
}
private void fireDataFullyLoaded() {
Runnable updater = new Runnable() {
public void run() {
transferBufferToMediaPlayer();
downloadingMediaFile.delete();
textStreamed.setText(("Download completed" ));
}
};
handler.post(updater);
}
public MediaPlayer getMediaPlayer() {
return mediaPlayer;
}
public void startPlayProgressUpdater() {
audiofiletime =mediaPlayer.getDuration();
float progress = (((float)mediaPlayer.getCurrentPosition()/ audiofiletime) * 100);
progressBar.setProgress((int)(progress));
//pb.setProgress((int)(progress*100));
if (mediaPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
startPlayProgressUpdater();
}
};
handler.postDelayed(notification,1000);
}
}
public void interrupt() {
playButton.setEnabled(false);
isInterrupted = true;
validateNotInterrupted();
}
/**
* Move the file in oldLocation to newLocation.
*/
public void moveFile(File oldLocation, File newLocation)
throws IOException {
if ( oldLocation.exists( )) {
BufferedInputStream reader = new BufferedInputStream( new FileInputStream(oldLocation) );
BufferedOutputStream writer = new BufferedOutputStream( new FileOutputStream(newLocation, false));
try {
byte[] buff = new byte[5461];
int numChars;
while ( (numChars = reader.read( buff, 0, buff.length ) ) != -1) {
writer.write( buff, 0, numChars );
}
} catch( IOException ex ) {
throw new IOException("IOException when transferring " + oldLocation.getPath() + " to " + newLocation.getPath());
} finally {
try {
if ( reader != null ){
writer.close();
reader.close();
}
} catch( IOException ex ){
Log.e(getClass().getName(),"Error closing files when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
}
}
} else {
throw new IOException("Old location does not exist when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
}
}
}