我在 Andriod 中开发了 Shoutcastinternet Radio Streaming(Stream URL http://123.176.41.8:8256
:),我能够成功地进行流式传输和播放。
但问题是:当我执行我的应用程序时,我能够连续播放和播放一段时间(20 分钟,半小时等......),
之后流停止(我无法播放流),有人可以帮忙吗?
在 Stream 停止后,我记录了错误。
The Error is:
D/dalvikvm(1238): GC_FOR_MALLOC freed 51742 objects / 1928072 bytes in 80ms(I'm repeating this statement in the log file while running my application on real Device)
更新:
例外:
04-27 18:31:05.753: V/MediaPlayer(26201): start
04-27 18:31:05.753: E/MediaPlayer(26201): start called in state 1
04-27 18:31:05.753: E/MediaPlayer(26201): message received msg=100, ext1=-38, ext2=0
04-27 18:31:05.753: E/MediaPlayer(26201): error (-38, 0)
04-27 18:31:05.753: E/MediaPlayer(26201): callback application
04-27 18:31:05.753: E/MediaPlayer(26201): back from callback
04-27 18:31:05.753: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.753: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.757: E/MediaPlayer(26201): Error (-38,0)
04-27 18:31:05.757: V/MediaPlayer-JNI(26201): reset
04-27 18:31:05.757: V/MediaPlayer(26201): reset
04-27 18:31:05.757: V/MediaPlayer-JNI(26201): start
04-27 18:31:05.757: V/MediaPlayer(26201): start
04-27 18:31:05.757: E/MediaPlayer(26201): start called in state 1
04-27 18:31:05.757: E/MediaPlayer(26201): message received msg=100, ext1=-38, ext2=0
04-27 18:31:05.757: E/MediaPlayer(26201): error (-38, 0)
04-27 18:31:05.757: E/MediaPlayer(26201): callback application
04-27 18:31:05.757: E/MediaPlayer(26201): back from callback
04-27 18:31:05.757: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.757: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.757: E/MediaPlayer(26201): Error (-38,0)
04-27 18:31:05.757: V/MediaPlayer-JNI(26201): reset
04-27 18:31:05.757: V/MediaPlayer(26201): reset
04-27 18:31:05.757: V/MediaPlayer-JNI(26201): start
04-27 18:31:05.757: V/MediaPlayer(26201): start
04-27 18:31:05.757: E/MediaPlayer(26201): start called in state 1
04-27 18:31:05.757: E/MediaPlayer(26201): message received msg=100, ext1=-38, ext2=0
04-27 18:31:05.757: E/MediaPlayer(26201): error (-38, 0)
04-27 18:31:05.757: E/MediaPlayer(26201): callback application
04-27 18:31:05.757: E/MediaPlayer(26201): back from callback
04-27 18:31:05.761: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.761: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.761: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.761: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.761: E/MediaPlayer(26201): Error (-38,0)
04-27 18:31:05.761: V/MediaPlayer-JNI(26201): reset
04-27 18:31:05.761: V/MediaPlayer(26201): reset
04-27 18:31:05.761: V/MediaPlayer-JNI(26201): start
04-27 18:31:05.761: V/MediaPlayer(26201): start
04-27 18:31:05.761: E/MediaPlayer(26201): start called in state 1
04-27 18:31:05.761: E/MediaPlayer(26201): message received msg=100, ext1=-38, ext2=0
04-27 18:31:05.761: E/MediaPlayer(26201): error (-38, 0)
04-27 18:31:05.761: E/MediaPlayer(26201): callback application
04-27 18:31:05.761: E/MediaPlayer(26201): back from callback
04-27 18:31:05.765: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.765: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.765: E/MediaPlayer(26201): Error (-38,0)
04-27 18:31:05.765: V/MediaPlayer-JNI(26201): reset
04-27 18:31:05.765: V/MediaPlayer(26201): reset
04-27 18:31:05.765: V/MediaPlayer-JNI(26201): start
04-27 18:31:05.765: V/MediaPlayer(26201): start
04-27 18:31:05.765: E/MediaPlayer(26201): start called in state 1
04-27 18:31:05.765: E/MediaPlayer(26201): message received msg=100, ext1=-38, ext2=0
04-27 18:31:05.765: E/MediaPlayer(26201): error (-38, 0)
04-27 18:31:05.765: E/MediaPlayer(26201): callback application
04-27 18:31:05.765: E/MediaPlayer(26201): back from callback
04-27 18:31:05.765: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.765: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.769: E/MediaPlayer(26201): Error (-38,0)
04-27 18:31:05.769: V/MediaPlayer-JNI(26201): reset
04-27 18:31:05.769: V/MediaPlayer(26201): reset
04-27 18:31:05.769: V/MediaPlayer-JNI(26201): start
04-27 18:31:05.769: V/MediaPlayer(26201): start
04-27 18:31:05.769: E/MediaPlayer(26201): start called in state 1
04-27 18:31:05.769: E/MediaPlayer(26201): message received msg=100, ext1=-38, ext2=0
04-27 18:31:05.769: E/MediaPlayer(26201): error (-38, 0)
04-27 18:31:05.769: E/MediaPlayer(26201): callback application
04-27 18:31:05.769: E/MediaPlayer(26201): back from callback
04-27 18:31:05.769: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.769: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.769: E/MediaPlayer(26201): Error (-38,0)
04-27 18:31:05.769: V/MediaPlayer-JNI(26201): reset
04-27 18:31:05.769: V/MediaPlayer(26201): reset
04-27 18:31:05.773: V/MediaPlayer-JNI(26201): start
04-27 18:31:05.773: V/MediaPlayer(26201): start
04-27 18:31:05.773: E/MediaPlayer(26201): start called in state 1
04-27 18:31:05.773: E/MediaPlayer(26201): message received msg=100, ext1=-38, ext2=0
04-27 18:31:05.773: E/MediaPlayer(26201): error (-38, 0)
04-27 18:31:05.773: E/MediaPlayer(26201): callback application
04-27 18:31:05.773: E/MediaPlayer(26201): back from callback
04-27 18:31:05.773: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.773: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.773: E/setupplayer(26201): java.io.FileNotFoundException: /data/data/com.torilt/cache/downloadingMediaFile591 (No such file or directory)
04-27 18:31:05.773: E/setupplayer(26201): Can't find file. Android must have deleted it on a clean up
04-27 18:31:05.773: E/MediaPlayer(26201): Error (-38,0)
04-27 18:31:05.773: V/MediaPlayer-JNI(26201): reset
04-27 18:31:05.773: V/MediaPlayer(26201): reset
04-27 18:31:05.776: V/MediaPlayer-JNI(26201): start
04-27 18:31:05.776: V/MediaPlayer(26201): start
04-27 18:31:05.776: E/MediaPlayer(26201): start called in state 1
04-27 18:31:05.776: E/MediaPlayer(26201): message received msg=100, ext1=-38, ext2=0
源代码:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Calendar;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.util.Log;
/**
* MediaPlayer does not yet support "Shoutcast"-like streaming from external
* URLs so this class provides a pseudo-streaming function by downloading the
* content incrementally & playing as soon as we get enough audio in our
* temporary storage.
*/
public class StreamingMediaPlayer extends Service {
final static public String AUDIO_MPEG = "audio/mpeg";
final static public String BITERATE_HEADER = "icy-br";
public int INTIAL_KB_BUFFER ;
private Handler handler;
//= 96*10/8
final public int BIT = 8;
final public int SECONDS = 60;
int bitrate = 56;
public File downloadingMediaFile;
final public String DOWNFILE = "downloadingMediaFile";
public Context context;
public int counter;
public int playedcounter;
public int preparecounter;
public MediaPlayer mp1;
public MediaPlayer mp2;
public boolean mp1prepared;
public boolean mp2prepared;
public boolean mp1preparing;
public boolean mp2preparing;
public boolean downloadingformp1;
public boolean downloadingformp2;
public boolean prepareState;
public String SONGURL = "";
// playing is "true" for mp1 and "false" for mp2
public boolean mp1playing;
public boolean started;
public boolean processHasStarted;
public boolean processHasPaused;
public boolean regularStream;
public BufferedInputStream stream;
public URL url;
public URLConnection urlConn;
public String station;
public String audiourl;
public Intent startingIntent = null;
public boolean stopping;
Thread preparringthread;
boolean waitingForPlayer;
// Setup all the variables
private void setupVars() {
counter = 0;
playedcounter = 0;
preparecounter = 0;
mp1 = new MediaPlayer();
mp2 = new MediaPlayer();
mp1prepared = false;
mp2prepared = false;
mp1preparing = false;
mp2preparing = false;
downloadingformp1 = false;
downloadingformp2 = false;
prepareState = true;
mp1playing = false;
started = false;
processHasStarted = false;
processHasPaused = true;
regularStream = false;
stream = null;
url = null;
urlConn = null;
station = null;
audiourl = null;
stopping = false;
preparringthread = null;
waitingForPlayer = false;
}
// This object will allow other processes to interact with our service
private final IStreamingMediaPlayer.Stub ourBinder = new IStreamingMediaPlayer.Stub() {
// String TAG = "IStreamingMediaPlayer.Stub";
public String getStation() {
// Log.d(TAG, "getStation");
return station;
}
public String getUrl() {
// Log.d(TAG, "getUrl");
return audiourl;
}
public boolean playing() {
// Log.d(TAG, "playing?");
return isPlaying();
}
public boolean pause() {
// Log.d(TAG, "playing?");
return isPause();
}
public void startAudio() {
// Log.d(TAG, "startAudio");
Runnable r = new Runnable() {
public void run() {
onStart(startingIntent, 0);
}
};
new Thread(r).start();
}
public void stopAudio() {
// Log.d(TAG, "stopAudio");
stop();
}
};
@Override
public void onCreate() {
super.onCreate();
context = this;
}
@Override
public void onStart(Intent intent, int startId) throws NullPointerException {
super.onStart(intent, startId);
// final String TAG = "StreamingMediaPlayer - onStart";
context = this;
setupVars();
if (intent.hasExtra("audiourl")) {
raiseThreadPriority();
processHasStarted = true;
processHasPaused = false;
audiourl = intent.getStringExtra("audiourl");
station = intent.getStringExtra("station");
downloadingMediaFile = new File(context.getCacheDir(), DOWNFILE+ counter);
downloadingMediaFile.deleteOnExit();
Runnable r = new Runnable() {
public void run() {
try {
startStreaming(audiourl);
} catch (IOException e) {
// Log.d(TAG, e.toString());
}
}
};
Thread t = new Thread(r);
t.start();
}
}
@Override
public void onDestroy() {
super.onDestroy();
mp1.stop();
mp2.stop();
}
@Override
public IBinder onBind(Intent intent) {
startingIntent = intent;
context = this;
return ourBinder;
}
@Override
public boolean onUnbind(Intent intent) {
super.onUnbind(intent);
stopSelf();
return true;
}
/**
* 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 {
try {
url = new URL(mediaUrl);
urlConn = (HttpURLConnection) url.openConnection();
urlConn.setReadTimeout(1000 * 20);
urlConn.setConnectTimeout(1000 * 5);
//The getContentType method is used by the getContent method to determine the type of the remote object; subclasses may find it convenient to override the getContentType method.
String ctype = urlConn.getContentType();
if (ctype == null) {
ctype = "";
} else {
ctype = ctype.toLowerCase();
}
if (ctype.contains(AUDIO_MPEG) || ctype.equals("")) {
String temp = urlConn.getHeaderField(BITERATE_HEADER);
if (temp != null) {
bitrate = new Integer(temp).intValue();
}
} else {
stopSelf();
return;
}
}
catch(NullPointerException ne)
{
}
catch (IOException ioe) {
// Log.e(TAG, "Could not connect to " + mediaUrl);
stopSelf();
return;
}
if (!regularStream) {
INTIAL_KB_BUFFER = bitrate * SECONDS / BIT;
Runnable r = new Runnable() {
public void run() {
try {
downloadAudioIncrement(mediaUrl);
Log.i("TAG12344444", "Unable to play");
stopSelf();
return;
} catch (IOException e) {
Log.i("TAG123", "Unable to initialize the MediaPlayer for Audio Url = "+mediaUrl, e);
stopSelf();
return;
} catch (NullPointerException e) {
stopSelf();
return;
}
}
};
Thread t = new Thread(r);
t.start();
}
}
/**
* Download the url stream to a temporary location and then call the
* setDataSource for that local file
*/
public void downloadAudioIncrement(String mediaUrl) throws IOException{
int bufsizeForDownload = 8 * 1024;
int bufsizeForfile = 64 * 1024;
stream = new BufferedInputStream(urlConn.getInputStream(),bufsizeForDownload);
Log.i("bufsize",Integer.toString(urlConn.getInputStream().available()));
try{
if(stream == null || stream.available() == 0){
stopSelf();
Log.i("unable to create ","stream null");
return;
}
}catch (NullPointerException e) {
stopSelf();
Log.i("return1","return1");
return;
}
BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(downloadingMediaFile), bufsizeForfile);
byte buf[] = new byte[bufsizeForDownload];
int totalBytesRead = 0, totalKbRead = 0, numread = 0;
do {
if (bout == null) {
counter++;
downloadingMediaFile = new File(context.getCacheDir(), DOWNFILE+ counter);
downloadingMediaFile.deleteOnExit();
bout = new BufferedOutputStream(new FileOutputStream(downloadingMediaFile), bufsizeForfile);
}
try {
numread = stream.read(buf);
} catch (IOException e) {
Log.d("Downloadingfile", "Bad read. Let's quit.");
// stop();
Log.i("return2","return2");
stopSelf();
// return;
}
catch (NullPointerException e) {
// Let's get out of here
e.printStackTrace();
break;
}
if (numread < 0) {
bout.flush();
stopSelf();
Log.i("Bad read from stream", "Bad read from stream3");
if(stream == null){
urlConn = new URL(mediaUrl).openConnection();
urlConn.setConnectTimeout(1000 * 30);
urlConn.connect();
stream = new BufferedInputStream(urlConn.getInputStream(),bufsizeForDownload);
}else{
handler.post(new Runnable() {
public void run() {
Log.i("Bad read from stream", "Bad read from xyz");
context.stopService(startingIntent);
Log.i("return3","return3");
return;
}
});
}
} else if (numread >= 1) {
bout.write(buf, 0, numread);
totalBytesRead += numread;
totalKbRead += totalBytesRead / 1000;
}
if (totalKbRead >= INTIAL_KB_BUFFER && stopping != true) {
bout.flush();
bout.close();
bout = null;
if (started == false) {
Runnable r = new Runnable() {
public void run() {
setupplayer();
}
};
Thread t = new Thread(r);
t.start();
}
totalBytesRead = 0;
totalKbRead = 0;
}
if (stopping == true) {
stream = null;
}
} while (stream != null);
}
/** oncompletelister for media player **/
class listener implements MediaPlayer.OnCompletionListener {
public void onCompletion(MediaPlayer mp) {
waitingForPlayer = false;
long timeInMilli = Calendar.getInstance().getTime().getTime();
long timeToQuit = (1000 * 30) + timeInMilli; // add 30 seconds
if (mp1playing)
{
mp1.reset();
removefile();
mp1prepared = false;
// Log.d(TAG, "mp1 is Free.");
if (downloadingformp2) {
if (mp2preparing && stopping == false) {
waitingForPlayer = true;
}
while (mp2preparing && stopping == false) {
if (timeInMilli > timeToQuit) {
stopSelf();
}
timeInMilli = Calendar.getInstance().getTime().getTime();
}
}
} else {
mp2.reset();
removefile();
mp2prepared = false;
if (downloadingformp1) {
if (mp1preparing && stopping == false) {
waitingForPlayer = true;
}
while (mp1preparing && stopping == false) {
if (timeInMilli > timeToQuit) {
stopSelf();
}
timeInMilli = Calendar.getInstance().getTime().getTime();
}
}
}
if (waitingForPlayer == true) {
// we must have been waiting
waitingForPlayer = false;
}
if (stopping == false) {
if (mp1playing) {
mp2.start();
mp1playing = false;
Runnable r = new Runnable() {
public void run() {
setupplayer();
}
};
Thread t = new Thread(r);
t.start();
} else {
mp1.start();
mp1playing = true;
Runnable r = new Runnable() {
public void run() {
setupplayer();
}
};
Thread t = new Thread(r);
t.start();
}
}
}
}
/** OnPreparedListener for media player **/
class preparelistener implements MediaPlayer.OnPreparedListener {
public void onPrepared(MediaPlayer mp) {
if (prepareState) {
prepareState = false;
mp1preparing = false;
mp1prepared = true;
if (started == false) {
started = true;
mp1.start();
mp1playing = true;
Runnable r = new Runnable() {
public void run() {
setupplayer();
}
};
Thread t = new Thread(r);
t.start();
}
} else {
prepareState = true;
mp2preparing = false;
mp2prepared = true;
}
}
};
/**
* Set Up player(s)
*/
public void setupplayer() {
final String TAG = "setupplayer";
Runnable r = new Runnable() {
public void run() {
try {
if (!mp1preparing && !mp1prepared) {
while (true) {
downloadingformp1 = true;
if (started == false)
break;
if (counter > preparecounter)
break;
}
File f = new File(context.getCacheDir(), DOWNFILE+ preparecounter);
FileInputStream ins = new FileInputStream(f);
mp1.setDataSource(ins.getFD());
mp1.setAudioStreamType(AudioManager.STREAM_MUSIC);//playing for live streaming
mp1.setOnCompletionListener(new listener());
mp1.setOnPreparedListener(new preparelistener());
if (started == false || waitingForPlayer == true){
}
mp1.prepareAsync();// .prepare();
mp1preparing = true;
downloadingformp1 = false;
preparecounter++;
} else if (!mp2preparing && !mp2prepared) {
while (true) {
downloadingformp2 = true;
if (started == false)
break;
if (counter > preparecounter)
break;
}
File f = new File(context.getCacheDir(), DOWNFILE+ preparecounter);
FileInputStream ins = new FileInputStream(f);
mp2.setDataSource(ins.getFD());
mp2.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp2.setOnCompletionListener(new listener());
mp2.setOnPreparedListener(new preparelistener());
mp2.prepareAsync();
mp2preparing = true;
downloadingformp2 = false;
preparecounter++;
// }
} else
Log.d(TAG, "No Media player is available to setup.");
return;
} catch (FileNotFoundException e) {
Log.e(TAG, e.toString());
Log.e(TAG,"Can't find file. Android must have deleted it on a clean up ");
stop();
return;
} catch (IllegalStateException e) {
Log.e(TAG, e.toString());
stop();
} catch (IOException e) {
Log.e(TAG, e.toString());
stop();
}
}
};
preparringthread = new Thread(r);
preparringthread.start();
try {
preparringthread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void removefile() {
File temp = new File(context.getCacheDir(), DOWNFILE + playedcounter);
temp.delete();
playedcounter++;
}
public boolean stop() {
final String TAG = "STOP";
stopping = true;
try {
if (mp1.isPlaying()){
if (!(stream == null)) {
Log.i("IN STOP", "MP1 is nill");
stopSelf();
}
mp1.stop();
}
if (mp2.isPlaying()){
Log.i("IN STOP", "MP2 is nill");
if (!(stream == null)){
stopSelf();
}
mp2.stop();
}
} catch (Exception e) {
Log.e(TAG, "error stopping players");
}
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.e(TAG, "error closing open connection");
}
}
stream = null;
processHasStarted = false;
processHasPaused = true;
if (preparringthread != null) {
preparringthread.interrupt();
}
stopSelf();
return true;
}
public boolean isPlaying() {
return processHasStarted;
}
public boolean isPause() {
return processHasPaused;
}
private void raiseThreadPriority() {
Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
}
}