简体   繁体   中英

Mediaplayer used in a service on Android 2.3

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:

  • Error(100, 0)
  • Error(-38, 0)

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

  • This is only a test-project made so I can understand the steps before implementing this into the app I'm working on
  • I left out parts of the VideoService class regarding communication to and from the Activity (since the crash is mediaplayer-related).
  • SurfaceViewHolder is a singleton used to keep various UI elements (such as a reference to the progress bar or currently available SurfaceView if any), useful for switching between Activities (with different UIs) and keeping the video playing (or keeping the audio in the background)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM