0

I'm making a music player, and there was a problem when switching to the next song. When the phone is in working condition (the screen is on) the tracks switch smoothly, when the screen is off there is a long pause, the song starts only after a long time (very long!!!) or when the screen is turned on. Also, everything works well with a headset (Bluetooth), songs switch smoothly even when the screen is turned off. I use MediaPlayer.prepare to prepare the track (music files are taken from the SD card, so I don't see any point in using MediaPlayer.prepareAsync()). Songs are played using Service. Since the player works fine when the screen is turned on and poorly when it is turned off, then this is the problem. I tried everything, searched all the articles about media player in Russian and English, reviewed YouTube. Help is also accepted on Kotlin. (here is the same question. but there is no answer. How to use wake lock for android mediaplayer?) Below is the code:

public class MusicService extends Service implements MediaPlayer.OnCompletionListener,
        MediaPlayer.OnPreparedListener {

    IBinder mBinder = new MyBinder();
    private MediaPlayer mediaPlayer = null;
    private Uri uri;
    private int position = POSITION_PLAY;
    public static AudioManager audioManager;
    int result;
    private NotificationReceiver notificationReceiver;

    @Override
    public void onCreate() {
        super.onCreate();

        notificationReceiver = new NotificationReceiver();
        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
                AudioManager.AUDIOFOCUS_GAIN);
        if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
            return;

        IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
        registerReceiver(notificationReceiver, intentFilter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        releaseMP();
        unregisterReceiver(notificationReceiver);
        audioManager.abandonAudioFocus(this);
        Log.e(TAG, "onDestroy()");
    }

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

    public class MyBinder extends Binder {
        MusicService getService() {
            return MusicService.this;
        }

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if(myPosition != -1){
            playMedia(myPosition);
        }
        return START_STICKY;
    }

    public void createMediaPlayer(int positionInner) {
        position = positionInner;
        uri = Uri.parse(musicFiles.get(position).getPath());
        mediaPlayer = null;
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try {
            mediaPlayer.setDataSource(getApplicationContext(), uri);
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        prepare();
    }

    private void playMedia(int position) {
        if(mediaPlayer != null) {
            mediaPlayer.stop();
            releaseMP();
        }
        createMediaPlayer(position);
        mediaPlayer.start();
    }

    public void prepare() {
        try {
            mediaPlayer.prepare();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }

    void showNotification(int playPauseBtn){
        ...
        startForeground(2, notification);
        if(!isGoing && IS_LIVE) {
            stopForeground(false);
        }
    }


    void OnCompleted(){
        mediaPlayer.setOnCompletionListener(this);
    }

    void OnPrepared() { mediaPlayer.setOnPreparedListener(this);}

    @Override
    public void onCompletion(MediaPlayer mp) {
        if(actionPlaying != null){
            actionPlaying.nextBtnClicked();
            if(mediaPlayer != null){
                mediaPlayer.start();
                OnCompleted();
            }
        }
    }

    private void releaseMP() {
        if (mediaPlayer != null) {
            try {
                mediaPlayer.release();
                mediaPlayer = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

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


public void start() {
    mediaPlayer.start();
}
public boolean isPlaying() {
    return mediaPlayer.isPlaying();
}
public void stop() {
    mediaPlayer.stop();
}
public void pause() {
    mediaPlayer.pause();
}
public void release() {
    releaseMP();
}
public int getDuration() {
    return mediaPlayer.getDuration();
}
public void seekTo(int position) {
    mediaPlayer.seekTo(position);
}
public int getCurrentPosition() {
    return mediaPlayer.getCurrentPosition();
}
}

Code for the method:

public void nextBtnClicked() {
        if(musicService.isPlaying()) {
            musicService.stop();
            musicService.release();
            if(SHUFFLE && !REPEAT){
                POSITION_PLAY = getRandom(ListSongs.size() - 1);
            }
            else if(!SHUFFLE && !REPEAT){
                POSITION_PLAY = ((POSITION_PLAY + 1) % ListSongs.size());
            }
            uri = Uri.parse(ListSongs.get(POSITION_PLAY).getPath());
            musicService.createMediaPlayer(POSITION_PLAY);
            if(is_live_player_activity) {
                metaData(uri);
            }
            musicService.OnCompleted();
            musicService.showNotification(R.drawable.ic_pause);
            playPauseBtn.setBackgroundResource(R.drawable.ic_pause);
            musicService.start();
        }
        else {
            musicService.stop();
            musicService.release();
            if(SHUFFLE && !REPEAT){
                POSITION_PLAY = getRandom(ListSongs.size() - 1);
            }
            else if(!SHUFFLE && !REPEAT){
                POSITION_PLAY = ((POSITION_PLAY + 1) % ListSongs.size());
            }
            uri = Uri.parse(ListSongs.get(POSITION_PLAY).getPath());
            musicService.createMediaPlayer(POSITION_PLAY);
            if(is_live_player_activity) {
                metaData(uri);
            }
            musicService.OnCompleted();
            if(FLAG){
                musicService.showNotification(R.drawable.ic_pause);
                playPauseBtn.setBackgroundResource(R.drawable.ic_pause);
            } else {
                musicService.showNotification(R.drawable.ic_play);
                playPauseBtn.setBackgroundResource(R.drawable.ic_play);
            }
        }
    }

Manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.music">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:name=".ApplicationClass"
        android:screenOrientation="portrait"
        android:theme="@style/Theme.Music">

        <activity android:name=".MusicActivity"
            android:screenOrientation="portrait"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        ...
        <service android:name=".MusicService" android:enabled="true"/>
        <receiver android:name=".NotificationReceiver" android:enabled="true">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
                <action android:name="android.media.AUDIO_BECOMING_NOISY" />
                <action android:name="actionprevious" />
                <action android:name="actionnext" />
                <action android:name="actionplay" />
            </intent-filter>
        </receiver>
    </application>

</manifest>
Draken
  • 3,134
  • 13
  • 34
  • 54
Alex Goodman
  • 21
  • 1
  • 5
  • Have you tried adding some logging to each step in the process, and checking the timestamps to see exactly which part is taking so long, and where it's different when the screen is on? How long is "a long time"? I'm guessing you're talking about tracks changing automatically when one ends (so manual skipping works fine) - you should probably post the code that handles that too (whatever `actionPlaying.nextBtnClicked()` does). If I had to guess, when the screen is off the phone is giving your app less priority, and all the work is taking longer- seems like a lot of steps, including external I/O – cactustictacs Nov 01 '21 at 19:14
  • @cactustictacs, Hello! Yes, I added Log, removed it so that it wouldn't be superfluous. Added nextBtnClicked. – Alex Goodman Nov 02 '21 at 06:31
  • @cactustictacs, As for how long - it does not play in any way before either turning on the screen or pressing the volume button – Alex Goodman Nov 02 '21 at 06:45

1 Answers1

0

I found a problem. It was necessary to call MediaPlayer.setwakemode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

Alex Goodman
  • 21
  • 1
  • 5