Search code examples
androidandroid-serviceandroid-mediaplayerandroid-service-binding

Android MediaPlayer to play video stream in Service screen rotation


I would like to create Activity with video player to play online stream using MediaPlayer class and SurfaceView to display. I'm creating MediaPlayer in separate Service so after screen rotation player don't have to be created again and don't have to connect to stream. My problem is that I don't know how to write Activity so my service wouldn't start every time after screen rotation.

My code below, in onStart() I start service but I don't know how to change it so it didn't start every time.

public class VideoPlayerActivity extends Activity implements SurfaceHolder.Callback {
    private String path;
    private SurfaceHolder vidHolder;
    private SurfaceView vidSurface;
    private VideoService videoService;
    private Intent playIntent;
    private boolean videoBound = false;

    private ServiceConnection musicConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            VideoService.VideoBinder binder = (VideoService.VideoBinder) service;
            videoService = binder.getService();
            videoService.setUrl(path);
            videoBound = true;
            if (vidHolder != null && videoService.getMediaPlayer() != null) {
                videoService.getMediaPlayer().setDisplay(vidHolder);
                videoService.playVideo();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            videoBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_player);
        path = "https://archive.org/download/ksnn_compilation_master_the_internet/ksnn_compilation_master_the_internet_512kb.mp4"; //TODO tmp
        playIntent = new Intent(this, VideoService.class);
        bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
        startService(playIntent);
        vidSurface = (SurfaceView) findViewById(R.id.surfView);
        vidHolder = vidSurface.getHolder();
        vidHolder.addCallback(VideoPlayerActivity.this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        if (videoService != null && videoService.getMediaPlayer() != null) {
            videoService.getMediaPlayer().setDisplay(vidHolder);
        } 
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        Log.d("ServiceConnection", "surfaceChanged  " + i + "   " + i1 + "   " + i2);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        Log.d("ServiceConnection", "surfaceDestroyed");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(musicConnection);
        stopService(playIntent);
        videoService = null;
    }
}

Service class:

public class VideoService extends Service implements OnPreparedListener {
    private MediaPlayer player;
    private String path;
    private final IBinder musicBind = new VideoBinder();

    @Override
    public void onCreate() {
        Log.d("VideoService", "onCreate");
        super.onCreate();
        player = new MediaPlayer();
        initMusicPlayer();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return musicBind;
    }

    @Override
    public boolean onUnbind(Intent intent){
        player.stop();
        player.release();
        return false;
    }

    public void initMusicPlayer() {
        player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
        player.setOnPreparedListener(this);
    }

    public void playVideo() {
        try {
            player.setDataSource(path);
            player.prepareAsync();
        } catch (IOException e) {}
    }

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        mediaPlayer.start();
    }

    public void setUrl(String url) {
        path = url;
    }

    public MediaPlayer getMediaPlayer() {
        return player;
    }

    public class VideoBinder extends Binder {
        public VideoService getService() {
            return VideoService.this;
        }
    }
}

Solution

  • You could either check for savedInstanceState being null to only start the service if the Activity is freshly created

    if (savedInstanceState == null) {
            startService...
    }
    

    or handle screen rotation yourself by adding

    android:configChanges="orientation|keyboardHidden|screenSize"
    

    to your Activity in manifest. Like this onCreate will not be called on rotation any more.