I have the following code written for a service in Android that plays video from a URL. The reason I am using a service is because I want the mediaplayer to keep the audio playing when switching from an activity with a surfaceview to one without (for example).
While the code works on Android 4.0+ devices, I am having trouble solving:
When running on Android 2.3 (Currently testing on a Samsung Galaxy S1).
Below you have the code for my service:
/**
* The MediaPlayer instance
*/
private MediaPlayer mediaPlayer;
/**
* Boolean value indicating if the service is running or not.
*/
private static boolean videoServiceRunning = false;
/**
* Boolean value indicating if the video is playing or not.
*/
private static boolean videoPlaying = false;
/**
* Boolean value indicating if the video has not been started yet or if it has ended playing.
*/
private static boolean videoPrepared = false;
@Override
public void onCreate() {
super.onCreate();
Log.i(LOGTAG, "Service Started.");
mediaPlayer = new MediaPlayer();
videoServiceRunning = true;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("MyService", "Service Stopped.");
videoServiceRunning = false;
try {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
setVideoPlaying(false);
}
mediaPlayer.release();
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(LOGTAG, "Received start id " + startId + ": " + intent);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnErrorListener(this);
return START_STICKY; // Run until explicitly stopped.
}
@Override
public IBinder onBind(Intent intent) {
Log.i(LOGTAG, "onBind");
return inMessenger.getBinder();
}
public static boolean isVideoServiceRunning()
{
return videoServiceRunning;
}
private void prepareVideo() {
try {
mediaPlayer.setDataSource(getApplicationContext(), Uri.parse(videoURL));
mediaPlayer.setScreenOnWhilePlaying(true);
mediaPlayer.prepare();
setVideoPrepared(true);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
String message = isNetworkAvailable() ?
getApplicationContext().getString(R.string.movie_unavailable) :
getApplicationContext().getString(R.string.network_error);
sendErrorMessageToActivity(message);
}
}
private void play() {
try {
mediaPlayer.start();
setVideoPlaying(true);
sendMessageToActivity(MEDIAPLAYER_PLAYING);
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
private void pause() {
try {
mediaPlayer.pause();
setVideoPlaying(false);
sendMessageToActivity(MEDIAPLAYER_PAUSED);
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
private void coupleSurface() {
try {
SurfaceHolder surfaceHolder = SurfaceViewHolder.getInstance().getSurfaceHolder();
mediaPlayer.setDisplay(surfaceHolder);
sendMessageToActivity(MEDIAPLAYER_SURFACE_COUPLED);
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
private void uncoupleSurface() {
try {
mediaPlayer.setDisplay(null);
sendMessageToActivity(MEDIAPLAYER_SURFACE_UNCOUPLED);
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
setVideoPlaying(false);
sendMessageToActivity(MEDIAPLAYER_ENDED);
}
@Override
public void onPrepared(MediaPlayer mp) {
sendMessageToActivity(ACTIVITY_VIDEO_PREPARED);
VideoService.videoDuration = mediaPlayer.getDuration();
VideoService.videoWidth = mediaPlayer.getVideoWidth();
VideoService.videoHeight = mediaPlayer.getVideoHeight();
Runnable updateProgressRunnable = new Runnable() {
@Override
public void run() {
if (videoServiceRunning) {
currentPosition = -1;
try {
currentPosition = mediaPlayer.getCurrentPosition();
}
catch (IllegalStateException e) {
Log.e(LOGTAG, "An exception has occurred while trying to retrieve the current position: "+ e);
}
if (currentPosition != -1) {
SurfaceViewHolder.getInstance().updateSeekBarProgress(currentPosition);
}
//TODO should the handler continue scheduling the runnable for execution in case of an exception?
handler.postDelayed(this, 1000);
}
}
};
handler.postDelayed(updateProgressRunnable, 1000);
SurfaceHolder surfaceHolder = SurfaceViewHolder.getInstance().getSurfaceHolder();
mediaPlayer.setDisplay(surfaceHolder);
if (playVideo) {
play();
}
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(LOGTAG, "What: "+what+", Extra: "+extra);
return false;
}
public static synchronized boolean isVideoPlaying() {
return VideoService.videoPlaying;
}
public static synchronized void setVideoPlaying(boolean videoPlaying) {
VideoService.videoPlaying = videoPlaying;
}
public static synchronized boolean isVideoPrepared() {
return videoPrepared;
}
public static synchronized void setVideoPrepared(boolean videoPrepared) {
VideoService.videoPrepared = videoPrepared;
}
Also, the logcat output:
09-24 15:10:57.671: D/VideoService(5561): handleMessage: 4
09-24 15:10:57.765: D/VideoService(5561): handleMessage: 0
09-24 15:10:57.765: I/MediaPlayer(5561): uri is:http://techslides.com/demos/sample-videos/small.mp4
09-24 15:10:57.765: I/MediaPlayer(5561): path is null
09-24 15:10:57.769: D/MediaPlayer(5561): Couldn't open file on client side, trying server side
09-24 15:11:00.679: D/VideoService(5561): handleMessage: 1
09-24 15:11:08.718: I/dalvikvm(5561): threadid=4: reacting to signal 3
09-24 15:11:08.730: I/dalvikvm(5561): Wrote stack traces to '/data/anr/traces.txt'
09-24 15:11:12.214: D/VideoService(5561): handleMessage: 7
09-24 15:11:15.722: W/IMediaDeathNotifier(5561): media server died
09-24 15:11:15.726: E/MediaPlayer(5561): error (100, 0)
09-24 15:11:15.726: W/AudioSystem(5561): AudioFlinger server died!
09-24 15:11:15.753: E/MediaPlayer(5561): Error (100,0)
09-24 15:11:15.753: E/VideoService(5561): What: 100, Extra: 0
09-24 15:11:15.812: D/VideoService(5561): handleMessage: 1
09-24 15:11:15.812: E/MediaPlayer(5561): start called in state 0
09-24 15:11:15.812: E/MediaPlayer(5561): error (-38, 0)
09-24 15:11:15.921: E/MediaPlayer(5561): Error (-38,0)
09-24 15:11:15.921: E/VideoService(5561): What: -38, Extra: 0
09-24 15:11:16.996: D/VideoService(5561): handleMessage: 1
09-24 15:11:16.996: E/MediaPlayer(5561): start called in state 0
09-24 15:11:17.000: E/MediaPlayer(5561): error (-38, 0)
09-24 15:11:17.003: E/MediaPlayer(5561): Error (-38,0)
09-24 15:11:17.007: E/VideoService(5561): What: -38, Extra: 0
Please keep in mind that
LE:
After returning true in onErrorListener for Errors 100 and -38 I get the following logcat output whenever I try to play the video. The Media Server died error is still present.
09-25 11:07:12.226: E/AndroidRuntime(7921): Set to default setting_6 : region=-Duser.region=US propRegn=US
09-25 11:07:15.378: E/AndroidRuntime(7930): Set to default setting_6 : region=-Duser.region=US propRegn=US
09-25 11:07:19.097: E/AndroidRuntime(7946): Set to default setting_6 : region=-Duser.region=US propRegn=US
09-25 11:07:30.027: E/MediaPlayerService(7886): MediaPlayerService::mIsAnyDrmVideoPlaying : 0
09-25 11:07:30.449: E/SecHardwareRenderer(7886): Unable to create the overlay!
09-25 11:07:30.449: A/SoftwareRenderer(7886): frameworks/base/media/libstagefright/colorconversion/SoftwareRenderer.cpp:59 mConverter.isValid()
09-25 11:07:35.167: E/dalvikvm(1566): Failed to write stack traces to /data/anr/traces.txt (1627 of 2166): No such file or directory
09-25 11:07:35.941: E/dalvikvm(1642): Failed to write stack traces to /data/anr/traces.txt (816 of 2839): No such file or directory
09-25 11:07:37.449: E/dalvikvm(7751): Failed to write stack traces to /data/anr/traces.txt (1162 of 2250): No such file or directory
09-25 11:07:37.449: E/dalvikvm(7787): Failed to write stack traces to /data/anr/traces.txt (-1 of 2249): Math result not representable
09-25 11:07:37.468: E/dalvikvm(7763): Failed to write stack traces to /data/anr/traces.txt (-1 of 2250): Math result not representable
09-25 11:07:37.476: E/dalvikvm(7803): Failed to write stack traces to /data/anr/traces.txt (-1 of 3216): Math result not representable
09-25 11:07:37.796: E/dalvikvm(7954): Failed to write stack traces to /data/anr/traces.txt (-1 of 2376): Math result not representable
09-25 11:07:37.800: E/dalvikvm(7744): Failed to write stack traces to /data/anr/traces.txt (-1 of 2241): Math result not representable
09-25 11:07:37.804: E/dalvikvm(7907): Failed to write stack traces to /data/anr/traces.txt (-1 of 2230): Math result not representable
09-25 11:07:37.929: E/dalvikvm(7829): Failed to write stack traces to /data/anr/traces.txt (10370 of 13387): No such file or directory
09-25 11:07:44.617: E/MediaPlayer(7954): error (100, 0)
09-25 11:07:44.625: E/MediaPlayer(7954): Error (100,0)
09-25 11:07:44.632: E/VideoService(7954): What: 100, Extra: 0
09-25 11:07:45.074: E/SoundBooster(7989): readSBTable: file open error!
09-25 11:07:45.074: E/AcousticEQ(7989): [AEQ] aeqcoe.txt: file open error!
09-25 11:07:46.117: E/AudioService(1462): Media server died.
09-25 11:07:46.125: E/AudioService(1462): Media server started.
Hopefully someone with more experience than me can help me out.
Thanks in advance!
Start called in state 0 (the -38) means you are calling start before properly setting the media and preparing. The 100 error is the media server died message. You are supplying invalid media and calling start anyway. You should add some if statements as safeguards before prepare and start, and handle error output in the onInfo and onError callbacks of the MediaPlayer.
Edit: In the onError handler, differentiate between fatal errors and non-fatal errors. Return true for non-fatal errors to indicate that the error was handled. Returning false tells the MediaPlayer
to call the onCompletion handler and stop. I see the "media server died" error quite often and it doesn't necessarily mean the media is invalid (as you have noted). Sorry I didn't notice that before.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.