繁体   English   中英

在Android 2.3的服务中使用的Mediaplayer

[英]Mediaplayer used in a service on Android 2.3

我为在Android中播放来自URL的视频的服务编写了以下代码。 我使用一项服务的原因是因为我希望媒体播放器在从具有Surfaceview的活动切换为不具有SurfaceView的活动时(例如)保持音频播放。

当代码在Android 4.0+设备上运行时,我无法解决以下问题:

  • 错误(100,0)
  • 错误(-38,0)

在Android 2.3上运行时(当前在Samsung Galaxy S1上进行测试)。

下面有您为我服务的代码:

/**
     * 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;
        }

另外,logcat输出:

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

请记住

  • 这只是一个测试项目,因此在将其实现到正在开发的应用程序中之前,我可以理解这些步骤
  • 我忽略了VideoService类中与Activity之间的通讯的部分(因为崩溃与Mediaplayer相关)。
  • SurfaceViewHolder是用于保留各种UI元素(例如,对进度条的引用或当前可用的SurfaceView,如果有的话)的单例,可用于在“活动”(具有不同的UI)之间切换以及保持视频播放(或将音频保留在后台) )

LE:

在onErrorListener中针对错误100和-38返回true之后,每当尝试播放视频时,都会得到以下logcat输出。 媒体服务器死亡错误仍然存​​在。

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.

希望比我有更多经验的人可以帮助我。

提前致谢!

在状态0(-38)下调用Start表示您在正确设置媒体和准备之前正在调用start。 100错误是介质服务器死亡消息。 您正在提供无效的媒体,并且仍在调用start。 您应该在准备和启动之前添加一些if语句作为保护措施,并处理MediaPlayer的onInfo和onError回调中的错误输出。

编辑:在onError处理程序中,区分致命错误和非致命错误。 对于非严重错误,返回true,以指示已处理该错误。 返回false告诉MediaPlayer调用onCompletion处理程序并停止。 我经常看到“媒体服务器死机”错误,这并不一定意味着媒体无效(如您所述)。 抱歉,我之前没有注意到。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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