Kace
Kace

Reputation: 43

Android MediaPlayer calls onCompletion before it already finished

I am trying to implement an Android Foreground Service that play music from a URL. MediaPlayer starts as normally and play the song, but after a while, it calls onCompletion() when the song is not finished. I set up an onErrorListener but it's not called.

What I have done:

  1. Checked the connection to the URL > OK
  2. Checked song duration > OK
  3. Implemented a partial wake lock > ?

The app doesn't crash, MediaPlayer just call onCompletion and I don't know what to do. Here you have the Service and Activity code. Thanks in advance:

SERVICE:

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

//FILTER FOR BROADCASTS
public final static String ACTION_FILTER = "ACTION_HHGROUPS";

//MEDIA ACTIONS:
public final static String ACTION_PLAY_ONE = "ACTION_PLAY_ONE";

//FOREGROUND:
public static boolean IS_FOREGROUND = false;
public final static int FOREGROUND_SERVICE = 101;
public final static String ACTION_START_FOREGROUND = "ACTION_START_FOREGROUND";
public final static String ACTION_STOP_FOREGROUND = "ACTION_STOP_FOREGROUND";

//EXTRAS:
public final static String EXTRA_URL = "EXTRA_URL";

private MediaPlayer mPlayer;

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    switch (intent.getAction()) {
        case ACTION_START_FOREGROUND:
            Log.v("SERVICIO", "ACTION_START_FOREGROUND");
            IS_FOREGROUND = true;
            showNotification();
            break;
        case ACTION_PLAY_ONE:
            Log.v("SERVICIO", "ACTION_PLAY_ONE");
            initializeMediaPlayer(
                intent.getStringExtra(MusicService.EXTRA_URL);
            break;
        case ACTION_STOP_FOREGROUND:
            Log.v("SERVICIO", "ACTION_STOP_FOREGROUND");
            IS_FOREGROUND = false;
            stopForeground(true);
            stopSelf();
            break;
    }
    return Service.START_STICKY;
}

public void initializePlayer(String url) {
    if(mPlayer == null) {
        mPlayer = new MediaPlayer();
        mPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
        mPlayer.setOnPreparedListener(this);
        mPlayer.setOnCompletionListener(this);
        mPlayer.setOnErrorListener(this);
        if(url != null && !url.isEmpty()) {
            try {
                mPlayer.setDataSource(url);
                mPlayer.prepareAsync();
            } catch (IOException e) {
                Log.v("SERVICIO-MEDIA", "IOException");
                e.printStackTrace();
            }
        }
    } else {
        try {
            mPlayer.reset();
            mPlayer.setDataSource(url);
            mPlayer.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@Override
public void onTaskRemoved(Intent rootIntent) {
    Log.e("SERVICIO", "OnTaskRemoved");
    if(IS_FOREGROUND)
        stopForeground(true);
    stopSelf();
}

@Override
public void onCompletion(MediaPlayer mediaPlayer) {
    Log.v("SERVICIO", "onCompletion");
}

@Override
public void onPrepared(MediaPlayer mediaPlayer) {
    mediaPlayer.start();
    Log.v("SERVICIO-MEDIA", "onPrepared. Duration: " + mediaPlayer.getDuration());
}

@Override
public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
    Log.v("SERVICIO", "onError");
    return true;
}

private void showNotification() {
    Intent notificationIntent = new Intent(this, PruebaActivity.class);
    notificationIntent.setAction(ACTION_NOTIFICATION_MAIN);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
            notificationIntent, 0);

    Intent previousIntent = new Intent(this, MusicService.class);
    previousIntent.setAction(ACTION_NOTIFICATION_PREV);
    PendingIntent ppreviousIntent = PendingIntent.getService(this, 0,
            previousIntent, 0);

    Intent playIntent = new Intent(this, MusicService.class);
    playIntent.setAction(ACTION_NOTIFICATION_PLAY);
    PendingIntent pplayIntent = PendingIntent.getService(this, 0,
            playIntent, 0);

    Intent nextIntent = new Intent(this, MusicService.class);
    nextIntent.setAction(ACTION_NOTIFICATION_NEXT);
    PendingIntent pnextIntent = PendingIntent.getService(this, 0,
            nextIntent, 0);

    Intent deleteIntent = new Intent(this, MusicService.class);
    PendingIntent pdeleteIntent = PendingIntent.getService(this, 666,deleteIntent,
            PendingIntent.FLAG_CANCEL_CURRENT);

    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle("Content title")
            .setTicker("This is a Ticker...")
            .setContentText("Context text")
            .setSmallIcon(R.drawable.ic_launcher_background)
            .setContentIntent(pendingIntent)
            .setOngoing(true)
            .addAction(android.R.drawable.ic_media_previous, "Prev",
                    ppreviousIntent)
            .addAction(android.R.drawable.ic_media_play, "Play",
                    pplayIntent)
            .addAction(android.R.drawable.ic_media_next, "Next",
                    pnextIntent).build();
    startForeground(FOREGROUND_SERVICE, notification);
}
}

ACTIVITY:

public class PruebaActivity extends AppCompatActivity implements View.OnClickListener {

String url = "http://stream.hhgroups.com/1-Ey7w3haY2RtcqiutMX1SylvqnvkP1oFuKo4765uI6Dc-Isusko%20y%20Sbrv%20-%20Marionetas%20(Adelanto)%20-%20www.HHGroups.com/";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_prueba);

    findViewById(R.id.btnPlaySong).setOnClickListener(this);
    Button btnForeground = findViewById(R.id.btnStartForeground);
    btnForeground.setOnClickListener(this);
    if(MusicService.IS_FOREGROUND)
        btnForeground.setText("STOP FOREGROUND");
    else
        btnForeground.setText("START FOREGROUND");
}

@SuppressLint("SetTextI18n")
@Override
public void onClick(View view) {
    switch(view.getId()) {
        case R.id.btnStartForeground:
            if(MusicService.IS_FOREGROUND) {
                Toast.makeText(PruebaActivity.this, "STOPPING FOREGROUND", Toast.LENGTH_SHORT).show();
                startService(new Intent(PruebaActivity.this, MusicService.class)
                        .setAction(MusicService.ACTION_STOP_FOREGROUND));
                ((Button)view).setText("START FOREGROUND");
            } else {
                Toast.makeText(PruebaActivity.this, "SETTING FOREGROUND", Toast.LENGTH_SHORT).show();
                startService(new Intent(PruebaActivity.this, MusicService.class)
                        .setAction(MusicService.ACTION_START_FOREGROUND));
                ((Button)view).setText("STOP FOREGROUND");
            }
            break;
        case R.id.btnPlaySong:
            if(MusicService.IS_FOREGROUND) {
                Log.v("SERVICIO-ACTIVITY", "btnPlaySong -> Foreground ON");
                Toast.makeText(PruebaActivity.this, "PLAYING SONG", Toast.LENGTH_SHORT).show();
                startService(new Intent(PruebaActivity.this, MusicService.class)
                        .setAction(MusicService.ACTION_PLAY_ONE)
                        .putExtra(MusicService.EXTRA_URL, url));
            } else {
                Log.v("SERVICIO-ACTIVITY", "btnPlaySong -> Foreground OFF");
                Toast.makeText(PruebaActivity.this, "SETTING FOREGROUND", Toast.LENGTH_SHORT).show();
                startService(new Intent(PruebaActivity.this, MusicService.class)
                        .setAction(MusicService.ACTION_START_FOREGROUND));
                Toast.makeText(PruebaActivity.this, "PLAYING SONG", Toast.LENGTH_SHORT).show();
                startService(new Intent(PruebaActivity.this, MusicService.class)
                        .setAction(MusicService.ACTION_PLAY_ONE)
                        .putExtra(MusicService.EXTRA_URL, url));
            }
            break;
    }
}
}

Upvotes: 1

Views: 566

Answers (1)

You Kim
You Kim

Reputation: 2795

Looks like a server side issue. Your test url has "Content-Disposition:inline;" in response header which means it is download not streaming.

HTTP/1.1 200 OK
Date: Fri, 28 Jul 2017 18:20:20 GMT
Server: Apache
Cache-Control: max-age=2678400
Content-Length: 10562918
Content-Disposition: inline; filename="540b4a08d51bc718f1e7f30313af9526.mp3"
Keep-Alive: timeout=10, max=800
Connection: Keep-Alive
Content-Type: audio/mpeg

Change your test url.

Upvotes: 1

Related Questions