Android MediaPlayer Streaming YouTube audio stream unexpected LOUD static - android

What I'm attempting:
I'm using youtube-dl in a Python Daemon on a remote server to get a URL.
That URL is fed into an Android App into a MediaPlayer instance.
What is happening:
Occasionally and unexpectedly the Media player will BLAST static and play at normal speed, sometimes it will blast static and play at 1.5 times speed.
Here's a video of what happens. HEADPHONE WARNING
YouTube Video
Observations:
If there is static it is for the whole song (it isn't intermittent).
I've taken the URLs it provides and they play fine in a PC browser with no static.
It happens on different phones, and it is not just my particular phone.
It takes longer to start tracks that end up being staticy.
Tracks that are staticy make my progress bar (seconds minutes display) just behave strangely. I've seen it count up and down in the first couple seconds, and there is the 1.5x speed I was talking about.
MediaHTTPConnection throws alot of exceptions that I don't know how to handle.
E/MediaHTTPConnectionEx: disconnecting
E/MediaHTTPConnectionEx: RuntimeException: Unbalanced enter/exit
mConnection.disconnect();
Below is the portion of my Python daemon that returns the URL
ydl_opts = {
'skip_download':True, # We just want to extract the info
'format':'bestaudio',
'forceurl':True,
'ignoreerrors':True,
'youtube_include_dash_manifest':False,
'restrict_filenames':True,
'source_address':'10.1.0.38',#we have to set this to force ipv4
'logger': MyLogger()
}
def ytdl(self, url):
url2 = "https://www.youtube.com/watch?v="+url
ydl.download([url2])
Here's the (basically boilerplate) MediaPlayer
public static Stack<Track> tracks = new Stack<>();
private static MediaPlayer mediaPlayer;
private String mediaFile;
private static int duration = 0;
private AudioManager audioManager;
private Boolean userPause = false;
// Binder given to clients
private final IBinder iBinder = new LocalBinder();
public static final String TAG = "Player";
#Override
public IBinder onBind(Intent intent) {
return iBinder;
}
class LocalBinder extends Binder {
Player getService() {
return Player.this;
}
}
public static void seekTo(int msec){
if(mediaPlayer != null){
mediaPlayer.seekTo(msec);
}
}
//The system calls this method when an activity, requests the service be started
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
boolean success = true;
//An audio file is passed to the service through putExtra();
if(intent.hasExtra("uri")){
mediaFile = intent.getStringExtra("uri");
} else {
stopSelf();
success = false;
}
//Request audio focus
if (!requestAudioFocus()) {
//Could not gain focus
Log.d(TAG, "error requesting audio focus");
stopSelf();
success = false;
}
if (mediaFile != null && !mediaFile.equals("") && success) {
Log.d(TAG, "Media File:" + mediaFile);
success = initMediaPlayer();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
//we cant destroy the player here because the back button fires this
//maybe i can not fire super?
super.onDestroy();
/*if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
removeAudioFocus();*/
}
private boolean initMediaPlayer() {
boolean error = false;
//one time setup
if(mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
//setup listeners
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
//Reset so that the MediaPlayer is not pointing to another data source
mediaPlayer.reset();
try {
Log.d(TAG, "setDataSource");
mediaPlayer.setDataSource(mediaFile);
} catch (IOException e) {
Log.e(TAG,"setDataSource error:"+e);
error = true;
}
try {
Log.d(TAG, "prepare");
mediaPlayer.prepare();
} catch (IOException e) {
Log.d(TAG, "prepare error");
e.printStackTrace();
error = true;
}
return error;
}
#Override
public void onPrepared(MediaPlayer mp) {
//Invoked when the media source is ready for playback.
Log.d(TAG, "onPrepared");
mp.start();
duration = mp.getDuration();
}
#Override
public void onCompletion(MediaPlayer mp) {
//Invoked when playback of a media source has completed.
removeAudioFocus();
mp.stop();
mp.reset();
}
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
//Invoked to communicate some info.
return false;
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
//Invoked indicating buffering status of
//a media resource being streamed over the network.
if(percent%25==0)
Log.d(TAG, "buffering:"+percent);
}
#Override
public void onSeekComplete(MediaPlayer mp) {
//Invoked indicating the completion of a seek operation.
Log.d(TAG, "onSeekComplete() current pos : " + mp.getCurrentPosition());
SystemClock.sleep(200);
start();
}
//Handle errors
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
//Invoked when there has been an error during an asynchronous operation
switch (what) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Log.e(TAG, "MEDIA ERROR NOT VALID FOR PROGRESSIVE PLAYBACK " + extra);
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Log.e(TAG, "MEDIA ERROR SERVER DIED " + extra);
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Log.e(TAG, "MEDIA ERROR UNKNOWN " + extra);
//NowPlaying.error = true;
break;
default:
Log.e(TAG, what + "," + extra);
break;
}
PlayerActivity.error = true;
return false;
}
#Override
public void onAudioFocusChange(int focusState) {
//Invoked when the audio focus of the system is updated.
switch (focusState) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
mediaPlayer.setVolume(1.0f, 1.0f);
if(!mediaPlayer.isPlaying()
&& !userPause) {
pause(false);
}
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
removeAudioFocus();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mediaPlayer.isPlaying()) mediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
private boolean requestAudioFocus() {
int result = 0;
if(audioManager == null) audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager != null) {
result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
Log.d(TAG, "requestAudioFocus:"+result);
return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
//Could not gain focus
}
private void removeAudioFocus() {
audioManager.abandonAudioFocus(this);
}
boolean isPlaying() {
if(mediaPlayer != null)
return mediaPlayer.isPlaying();
return false;
}
//pause(true) == pause
//pause(false) == play
//this is used by the system
void pause(Boolean state){
//pause
if (state) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
} else {
if (!mediaPlayer.isPlaying()) {
start();
}
}
}
//this is a pause toggle that is only triggered by the pause/play button
boolean pause() {
if (mediaPlayer.isPlaying()){
userPause = true;
mediaPlayer.pause();
} else {
userPause = false;
start();
}
return !mediaPlayer.isPlaying();
}
void start(){
mediaPlayer.start();
}
int getCurrentPosition(){
if(mediaPlayer != null)
return mediaPlayer.getCurrentPosition();
return 0;
}
int getDuration(){
return duration;
}
}

I feel like someone else is going to have this problem so I'm going to post my solution.
So I noticed a mime type error popped up for every track. The error still shows up now that I've fixed this problem but the loud static has stopped.
Here is the error that started the wheels turning:
E/MediaHTTPConnectionEx: getMIMEType
[seekToEx] offset:0/mCurrentOffset:-1
I noticed some of the URLs youtube-dl was giving me for the webm didn't have a mime type specified in the URL.
Here is an example:
...O8c2&mime=&pl=...
But all of the m4a streams had a mime type in the URL
...70F61&mime=audio%2Fmp4&itag=140&key...
So I think that while my solution isn't the best solution, it's the easiest. Since ALL the m4a streams had a mime specified I just limited myself to those streams.
The rub is this:
I'm pretty sure that if I just checked the URL for a specified mime field I could still play most webm files. The only ones that were failing (staticy) were URLs that did not have that field.
My solution:
Python only pulls m4a files:
...
'format':'bestaudio[ext=m4a]',
...
Android now passes hard coded headers:
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "audio/mp4"); // change content type if necessary
Uri uri = Uri.parse(mediaFile);
Log.d(TAG, "getMimeType="+getMimeType(uri));//this is ALWAYS null
mediaPlayer.setDataSource(getApplicationContext(), uri, headers);

Related

How to pause video when other app play music and resume once the music stops?

When the video is playing and I resume the music from notification in the Music app, the video is still playing. Both music and video are playing concurrently. What I want is to pause the video when the music is started. Youtube app does what I am explaining here. When googled, I found that AudioFocus is used for MediaPlayer in such cases. Does VideoView support AudioFocus if yes then how to use that to achieve above goal?
You can call changeAudioFocus(true);
when you start playing media from your app. It will create an OnAudioFocusChangeListener and set it with AudioManager, and you will get a callback when you get AUDIOFOCUS_LOSS or AUDIOFOCUS_LOSS_TRANSIENT message.
You also get AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK, which is used to lower the volume of the player, which some media players do when you get a notification sound.
/**
* Used to indicate a transient loss of audio focus where the loser of the audio focus can
* lower its output volume if it wants to continue playing (also referred to as "ducking"), as
* the new focus owner doesn't require others to be silent.
* #see OnAudioFocusChangeListener#onAudioFocusChange(int)
*/
code
private final OnAudioFocusChangeListener mAudioFocusListener = createOnAudioFocusChangeListener();
private AudioManager mAudioManager = null;
private boolean mHasAudioFocus = false;
private void changeAudioFocus(boolean acquire) {
if (mAudioManager == null)
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
if (mAudioManager == null)
return;
if (acquire) {
if (!mHasAudioFocus) {
final int result = mAudioManager.requestAudioFocus(mAudioFocusListener,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
mAudioManager.setParameters("bgm_state=true");
mHasAudioFocus = true;
}
}
} else if (mHasAudioFocus) {
mAudioManager.abandonAudioFocus(mAudioFocusListener);
mAudioManager.setParameters("bgm_state=false");
mHasAudioFocus = false;
}
}
private OnAudioFocusChangeListener createOnAudioFocusChangeListener() {
return new OnAudioFocusChangeListener() {
int audioDuckLevel = -1;
private int mLossTransientVolume = -1;
private boolean wasPlaying = false;
#Override
public void onAudioFocusChange(int focusChange) {
/*
* Pause playback during alerts and notifications
*/
switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS:
if (BuildConfig.DEBUG) Log.i(TAG, "AUDIOFOCUS_LOSS");
// Pause playback
changeAudioFocus(false);
pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
if (BuildConfig.DEBUG) Log.i(TAG, "AUDIOFOCUS_LOSS_TRANSIENT");
// Pause playback
pausePlayback();
break;
case AudioManager.AUDIOFOCUS_GAIN:
if (BuildConfig.DEBUG) Log.i(TAG, "AUDIOFOCUS_GAIN: ");
// Resume playback
if (mLossTransientVolume != -1) {
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mLossTransientVolume, 0);
mLossTransientVolume = -1;
}
if (mLossTransient) {
if (wasPlaying && mSettings.getBoolean("resume_playback", true))
play();
mLossTransient = false;
}
break;
}
}
private void pausePlayback() {
if (mLossTransient) return;
mLossTransient = true;
wasPlaying = isPlaying();
if (wasPlaying) pause();
}
};
}

Loop buffered video after getting error in videoView android

I want to repeat buffered video after getting error in the VideoView
I have play my video with the following code:
public void playVideo() {
if (!isAdded()) {
return;
}
try {
// Get the URL from String VideoURL
Uri video = Uri.parse("http://www.sample-videos.com/video/mp4/480/big_buck_bunny_480p_20mb.mp4");
videoView.setMediaController(new MediaController(
getActivity()));
videoView.setVideoURI(video);
} catch (Exception e) {
ApplicationClass.gLogger.out("Error Happened in initializing ");
e.printStackTrace();
}
videoView.requestFocus();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
// Close the progress bar and play the video
public void onPrepared(MediaPlayer mp) {
videoView.start();
mp.setLooping(true);
}
});
videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
//playVideo again;
if (i == MediaPlayer.MEDIA_ERROR_SERVER_DIED || i == MediaPlayer.MEDIA_ERROR_IO || i == MediaPlayer.MEDIA_ERROR_UNKNOWN) {
mediaPlayer.reset();
}
return true;
}
});
}
every thing is ok, but when I lost my connection my video not looping.
on Error listener called with MediaPlayer.MEDIA_ERROR_IO. I want to loop my buffered video.
what I have tried in onError listener?
call playVideo() method again.
use mediaPlayer.seekTo() and mediaPlayer.start().
use videoView.seekTo().
I search a lot in SO and see many links but not worked for me.
as we can't get buffer data from VideoView, I can't save buffer data to a file and read from that.
thanks in advance
// UPDATE
seek not working in videoView because as in source of VideoView mentioned, when we call seek method following method called:
private boolean isInPlaybackState() {
return (mMediaPlayer != null &&
mCurrentState != STATE_ERROR &&
mCurrentState != STATE_IDLE &&
mCurrentState != STATE_PREPARING);
}
as mCurrentState is STATE_ERROR seek not work any more, but i can't figure out how to fix my issue yet.
Maybe it's be helpful:
textureView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
//it,s be called without isInPlaybackState()
mp.seekTo(second);
return false;
}
});
It's just recommendation how bypass calling isInPlaybackState().

MediaPlayer on Single Thread

I am implementing a game, and I want to use one and only one MediaPlayer instance, running in a separate thread from the UI. Each audio file is sent to a FIFO queue, and played immediately if no file is playing, or as soon as the previous file in the queue is finished.
I have implemented a singleton class to support this as follows:
public class ThePlayer {
private static ThePlayer instance = null;
private Context context;
Thread playerThread;
BlockingQueue<Integer> listIDs = new LinkedBlockingQueue<Integer>();
MediaPlayer player;
Integer playID;
private ThePlayer() {
player = null;
playerThread = new Thread(new Runnable() {
//Object locker = new Object();
public void run() {
while (true) {
try {
playID = listIDs.take(); // blocks if list empty
Log.d(this.getClass().getName(), "Took ID 0x" + Integer.toHexString(playID));
player = MediaPlayer.create(context, playID);
player.setOnCompletionListener(
new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
mp = null;
synchronized (playerThread) {
Log.d(this.getClass().getName(), "Finished playing 0x"+Integer.toHexString(playID));
playerThread.interrupt();
}
}
});
player.start();
Log.d(this.getClass().getName(), "Started playing 0x"+Integer.toHexString(playID));
synchronized (this) {
Log.d(this.getClass().getName(), "Now wait to finish");
wait(); // until finished playing
}
} catch (InterruptedException ie) {
Log.d(getClass().getName(), "Player thread wait interrupted");
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
playerThread.setName("PlayerThread");
playerThread.start();
}
public static ThePlayer getInstance()
{
if(instance == null)
{
instance = new ThePlayer();
}
return instance;
}
public void play(Context _ctx, int id) {
context = _ctx;
listIDs.add(id);
Log.d(this.getClass().getName(), "Added ID 0x" + Integer.toHexString(id));
}
public void stop() {
//TODO: implement
}
}
In general, this works well, but one particular file fails to play in an inconsistent manner. In other words, in most cases, it does not play, but occasionally it does. All the log entries indicate that the file is queued, the MediaPlayer is allocated and started, and that the onCompletion function is called. At no point is an exception thrown.
This happens on a Motorola Defy+ phone and various emulator configurations. It does not happen on my Samsung Galaxy Tab II 10.1, and my guess is that is a function of more capable hardware, or possibly the more advanced version of Android.

Android MediaPlayer stops on onBackPressed

I have lots of problems with MediaPlayer.
It's likely pertaining to old OS versions, at least until 2.3.
One sound is playing fine in a certain Activity (right before launching another)
When I pop the second Activity to go back to the first one, I play the sound file right before the popping (I use super.onBackPressed).
On these old devices (~2.3), the sound file is cut off.
I use the same way of launching and playing the MediaPlayer.
I create the MediaPlayer using create (synched). I retain the MediaPlayer by putting it in a static container. I released end empty the container only on setOnCompletionListener. What's going on..
Here's some code...
// Start sound
adhocplaysoundstatic(R.raw.soundfile, getApplicationContext());
// Pop activity
super.onBackPressed();
Definition
static ArrayList<MediaPlayer> staticplayers = new ArrayList<MediaPlayer>();
static public void adhocplaysoundstatic(final int MEDIA, Context context) {
MediaPlayer player = getMediaPlayerStatic(MEDIA, context);
staticplayers.add(player); // Hold on to
player.setOnCompletionListener(new OnCompletionListener() {
#Override public void onCompletion(MediaPlayer mp) {
mp.release();
staticplayers.remove(mp);
}
});
player.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
Log.d(LOG_TAG, "onPrepared, play!");
mp.start();
}});
//player.start();
}
More...
static protected MediaPlayer getMediaPlayerStatic(int id, Context context) throws RuntimeException {
MediaPlayer player = MediaPlayer.create(context, id);
if (player == null) {
throw new RuntimeException("Failed creating media player from id " + id);
}
else {
player.setOnErrorListener(new OnErrorListener() {
#Override public boolean onError(MediaPlayer mp, int what, int extra) {
Log.d(LOG_TAG, "MediaPlayer error: " + mp.toString() + ", what: " + what + ", extra: " + extra);
return false;
}
});
}
return player;
}

How do Android mediaplayers continuing playing songs when app is closed?

Wondering how next songs are played once app is closed as if playing an entire CD or playlist...
The media player only plays one audio track. What media players do, is listen on the onCompletion event and play the next track.
The MediaPlayer is bound to the process, not the activity, so it keeps playing as long as the process runs. The activity might be paused or destroyed, but that won't affect the internal thread that MediaPlayer uses.
I'm building an audio player to learn Android, you can see the service that plays audio files here
edit
regarding the first comment: The service keeps running on the background and keeps running after you "exit" the application, because the lifecycle of the service and Activities are different.
In order to play the next track, the service registers a callback on the MediaPlayer so the service is informed when an audio stream completed. When the audio completes, the service cleans up the resources used by the MediaPlayer, by calling MediaPlayer.release(), and then creates a fresh new media player with the next audio track to play and registers itself to be notified again when that audio track completes, ad infinitum :).
The MediaPlayer class doesn't understand playlists, so the service is responsible for playing a track after the previous track completes.
In the AudioPlayer service I've created, an activity queues tracks in the AudioPlayer and the AudioPlayer is responsible for playing them in order.
I hope it's clear and again, if you have some time, please check the code of AudioPlayer service I've put above. It's not pure beauty, but it does its job.
You can create a Service to keep the MediaPlayer playing after your app either exits or is paused. To get the MediaPlayer to play consecutive tracks you can register an onCompletionListener that will decide which track to play next. Here is a simple example service that does this:
package edu.gvsu.cis.muzak;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
public class MuzakService extends Service {
private static final String DEBUG_TAG = "MuzakService";
private MediaPlayer mp;
private String[] tracks = {
"http://freedownloads.last.fm/download/288181172/Nocturne.mp3",
"http://freedownloads.last.fm/download/367924875/Behemoths%2BSternentanz.mp3",
"http://freedownloads.last.fm/download/185193341/Snowflake%2BImpromptu.mp3",
"http://freedownloads.last.fm/download/305596593/Prel%25C3%25BAdio.mp3",
"http://freedownloads.last.fm/download/142005075/Piano%2BSonata%2B22%2B-%2Bmovement%2B2%2B%2528Beethoven%2529.mp3",
"http://freedownloads.last.fm/download/106179902/Piano%2BSonata%2B%25231%2B-%2Bmovement%2B%25234%2B%2528Brahms%2529.mp3",
};
private int currentTrack = 0;
#Override
public void onCreate() {
super.onCreate();
Log.d(DEBUG_TAG, "In onCreate.");
try {
Uri file = Uri.parse(tracks[this.currentTrack]);
mp = new MediaPlayer();
mp.setDataSource(this, file);
mp.prepare();
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
currentTrack = (currentTrack + 1) % tracks.length;
Uri nextTrack = Uri.parse(tracks[currentTrack]);
try {
mp.setDataSource(MuzakService.this,nextTrack);
mp.prepare();
mp.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
} catch (Exception e) {
Log.e(DEBUG_TAG, "Player failed", e);
}
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.d(DEBUG_TAG, "In onDestroy.");
if(mp != null) {
mp.stop();
}
}
#Override
public int onStartCommand(Intent intent,int flags, int startId) {
super.onStart(intent, startId);
Log.d(DEBUG_TAG, "In onStart.");
mp.start();
return Service.START_STICKY_COMPATIBILITY;
}
#Override
public IBinder onBind(Intent intent) {
Log.d(DEBUG_TAG, "In onBind with intent=" + intent.getAction());
return null;
}
}
You can start this Service up in an Activity as follows:
Intent serv = new Intent(this,MuzakService.class);
startService(serv);
and stop it like this:
Intent serv = new Intent(this,MuzakService.class);
stopService(serv);
Please note that Service run in fore ground too.
Please see the official documentation. It explains with a sample code.
Using a Service with MediaPlayer:
http://developer.android.com/guide/topics/media/mediaplayer.html#mpandservices
Running as a foreground service
Services are often used for performing background tasks
But consider the case of a service that is playing music. Clearly this is a service that the user is actively aware of and the experience would be severely affected by any interruptions. Additionally, it's a service that the user will likely wish to interact with during its execution. In this case, the service should run as a "foreground service." A foreground service holds a higher level of importance within the system—the system will almost never kill the service, because it is of immediate importance to the user. When running in the foreground, the service also must provide a status bar notification to ensure that users are aware of the running service and allow them to open an activity that can interact with the service.
In order to turn your service into a foreground service, you must create a Notification for the status bar and call startForeground() from the Service
mediap player should run from the service, here i have passed the arraylist of songs from the activity to service and all the songs are run by reading the arraylist
public class MyService extends Service implements OnCompletionListener,
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener{
Context context;
private static final String ACTION_PLAY = "PLAY";
private static final String TAG = "SONG SERVICE";
MediaPlayer mediaPlayer;
private int currentTrack = 0;
ArrayList<String> list;
public MyService() {
context=getBaseContext();
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
list = (ArrayList<String>)intent.getSerializableExtra("arraylist");
int count=0;
Log.d(TAG, "total count:"+list.size());
//playing song one by one
for (String string : list) {
//play(string);
count++;
Log.d(TAG, "count:"+list);
}
play(currentTrack);
Log.d(TAG, "count:"+count);
if(count==list.size()){
//stopSelf();
Log.d(TAG, "stoping service");
//mediaPlayer.setOnCompletionListener(this);
}else{
Log.d(TAG, "not stoping service");
}
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
Log.d(TAG, "oncommat");
}
return START_STICKY;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service was Created", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(Intent intent, int startId) {
// Perform your long running operations here.
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
Log.d("service", "destroyed");
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
}
private void play(int id) {
if(mediaPlayer!=null && mediaPlayer.isPlaying()){
Log.d("*****begin*****", "playing");
stopPlaying();
Log.d("*****begin*****", "stoping");
} else{
Log.d("*****begin*****", "nothing");
}
Log.d("*****play count*****", "="+currentTrack);
Log.i("******playing", list.get(currentTrack));
Uri myUri1 = Uri.parse(list.get(id));
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
//mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mediaPlayer.setOnPreparedListener(this);
//mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
try {
mediaPlayer.setDataSource(context, myUri1);
Log.i("******playing", myUri1.getPath());
} catch (IllegalArgumentException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
try {
mediaPlayer.prepare();
} catch (IllegalStateException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
}
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
currentTrack=currentTrack+1;
play(currentTrack);
/* currentTrack = (currentTrack + 1) % list.size();
Uri nextTrack=Uri.parse(list.get(currentTrack));
try {
mediaPlayer.setDataSource(context,nextTrack);
mediaPlayer.prepare();
// mediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}*/
}
});
mediaPlayer.start();
}
private void stopPlaying() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
#Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
}
The answer is Services in Android as described here: http://developer.android.com/guide/topics/fundamentals.html as
You are going to create a service and when you receive play command from your app, your app will send a message to background service to play the music. Services do not run in foreground, therefore even you put your screen to sleep, it plays the music.
Playing BG Music Across Activities in Android

Categories

Resources