I'm developing a test app that when the automated testing process finishes an alarm sound is played to notify the operator.
This sound is a 3secs duration alarm ringtone, and I need to be played in loop until the user touches the phone screen.
This is the way I implement the mediaplayer:
mp = MediaPlayer.create(MainActivity.this, R.raw.alarm);
try {
mp.prepare();
mp.setLooping(true);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
I have defined the mp.setLooping that should make the sound play continuosly, but it doesn't.
Then, to stop the sound touching the screen:
#Override
public boolean onTouchEvent (MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
/*If sound is playing, stops*/
if (mp.isPlaying()) {
mp.stop();
}
return true;
}
return super.onTouchEvent(event);
}
So if mp.setLooping is not working, how should I make the sound play continuosly?
When you instantiate a MediaPlayer with create(), it is returned in a prepared state and you must not call prepare() on it. In your case, this is throwing an Exception, and therefore mp.setLooping(true) isn't being called.
mp = MediaPlayer.create(MainActivity.this, R.raw.alarm);
mp.start();
mp.setLooping(true);
Related
So I put an audio file in my application and it's supposted play when I touch the button and stop when I touch it again.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button one = (Button) findViewById(R.id.buttonId);
final MediaPlayer mp = new MediaPlayer();
one.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
if(mp.isPlaying())
{
mp.stop();
}
try {
mp.reset();
AssetFileDescriptor afd;
afd = getAssets().openFd("mosq.mp3");
mp.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
mp.prepare();
mp.setLooping(true);
mp.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
here is my code, this part:
if(mp.isPlaying())
{
mp.stop();
}
didn't work for some reason.
Make sure you put a return statement below mp.stop().
From what I can understand the sound does stop but then it starts again because the next part of the code still gets executed
As George D correctly pointed out, you start the media playing unconditionally, even if you just stopped it. You could use his solution or do something like:
if(mp.isPlaying())
{
mp.stop();
}
else {
try {
mp.reset();
AssetFileDescriptor afd;
afd = getAssets().openFd("mosq.mp3");
mp.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
mp.prepare();
mp.setLooping(true);
mp.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
This has several other potential bugs in it:
* I'm not sure if this is what you intended but the player won't ever pause, just stop and restart from the beginning. If you try to resume or play again it'll completely reload the audio file every time. At a minimum this is a waste of resources, plus it's likely not the expected behavior from a UI perspective.
* You don't want to define the MediaPlayer object as a local variable within the OnCreate method. The only reason this works at all is you have a memory leak (you never unsubscribe your event handler for the click); if you didn't have the memory leak the object would become eligible for garbage collection as soon as you completed the onCreate method and, as far as the framework was concerned, it would no longer exist.
I've got an app where Ii want to sound the alarm ringtone and raise the volume each second.
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
player = MediaPlayer.create(getApplicationContext(), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
After initializing AudioManager and MediaPlayer, I've got a method which is executed each second when some circumstances occur. The method is the next one:
private void sound() {
if (!player.isPlaying()) {
try {
player.setLooping(true);
player.setVolume(5,5);
} catch (Exception e) {
e.printStackTrace();
}
player.start();
} else {
audioManager.adjustStreamVolume(AudioManager.STREAM_NOTIFICATION,AudioManager.ADJUST_RAISE,0);
}
}
As you can see, the first time the method is executed the sound begins, that works OK. But when is already started and I want to raise the volume, the adjustStreamVolume makes nothing.
Any help or advice?
I am having an odd issue where my audio file sometimes plays and sometimes does not play. The catch is that when it decides to not play, the DDMS gives me an:
E/MediaPlayer﹕ Should have subtitle controller already set
Because this is one-to-one with the music not playing, I have determined that this is probably the issue...
If the music is not playing and I hit the volume button it begins to play.
If I wait about 30 seconds of no-play, it begins to start again (not looping).
Whats going on here? I am on KitKat using
player = new MediaPlayer();
AssetFileDescriptor afd = null;
try {
afd = getAssets().openFd("Theme.mp3");
} catch (IOException e) {
e.printStackTrace();
}
try {
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
} catch (IOException e) {
e.printStackTrace();
}
try {
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
player.setLooping(true); //restart playback end reached
//player.setVolume(1, 1); //Set left and right volumes. Range is from 0.0 to 1.0
player.start(); //start play back
Looking at a previous discussion on StackOverflow, and the referenced Android commit where this was introduced, the code above might not completely initialize the MediaPlayer object.
The KitKat example code for media playback suggests that you should call:
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
immediately after you construct the MediaPlayer, and before you call its setDataSource method.
I had the same issue and I fixed it by adding the following right after instantiating MediaPlayer.
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
if (mp == mediaPlayer) {
mediaPlayer.start();
}
}
});
Previously I was implementing MediaPlayer.OnPreparedListener and overriding onPrepared() but it didn't work.
I hope this helps!
This should fix your problem (did for me): Replace the line that says "player.start()" following the rest of your code with an async callback like so:
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
This error is just a Log.e, not a real error. It shouldn't cause your player to not play, I'm guessing it's just because the player hadn't finished preparing when you try to call start().
E/MediaPlayer﹕ Should have subtitle controller already set
Its been a long time since I was working on this app. Here is what I ended up doing to get this to work. (Tested on KitKat and Lollipop). I think switching from MediaPlayer to APMediaPlayer was part of the trick.
#Override
public void onDestroy() {
if(player != null) {
player.release();
player = null;
}
super.onDestroy();
}
#Override
public void onStart() {
super.onStart();
if(player != null) {
player.start();
}
else {
player = new APMediaPlayer(this); //create new APMediaPlayer
player.setMediaFile("Theme.mp3"); //set the file (files are in data folder)
player.start(); //start play back
player.setLooping(true); //restart playback end reached
player.setVolume(1, 1); //Set left and right volumes. Range is from 0.0 to 1.0
}
}
#Override
public void onResume() {
super.onResume();
if(player != null) {
player.start();
}
}
set in manifest file may help you
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
I have a problem with the built-in media controls, which appear on the lock screen when music is playing through the mediaplayer.
When the music is playing the controls are always present, but when i press the pause button on the lock screen and pause the mediaplayer through mediaplayer.pause() and then turn off the screen and turn it on again (to see the lock screen again), the media controls have vanished, although the player is only paused and not stopped.
With the built-in music player app, which also uses the mediaplayer, this does not happen.
Here are the relevant code sections:
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
if(userPresent)
int result = mAudioManager.requestAudioFocus(mAudioFocusListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
configMediaPlayer();
}
userPresent = false;
}
screenOn = false;
}
else if (action.equals(Intent.ACTION_USER_PRESENT)) {
stopMediaPlayer();
userPresent = true;
}
The code is inside a broadcastreceiver. The music shall only be played when the screen is off (a partial wakelock is held) or the lock screen is present.
private void configMediaPlayer(){
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mediaPlayer.setOnPreparedListener(this);
}
else
mediaPlayer.reset();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(getApplicationContext(), Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.song));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.prepareAsync();
}
#Override
public void onPrepared(MediaPlayer mp) {
startMediaPlayer();
}
private void startMediaPlayer(){
mediaPlayer.setLooping(true);
mediaPlayer.start();
}
private void stopMediaPlayer(){
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
The function for the pause event:
public void pause(){
if(isPaused && !userPresent){
startMediaPlayer();
Intent i = new Intent("com.android.music.playstatechanged");
i.putExtra("position", Long.valueOf(123));
i.putExtra("playing", true);
sendStickyBroadcast(i);
isPaused = false;
}
else if (!isPaused && !userPresent){
mediaPlayer.pause();
isPaused = true;
Intent i = new Intent("com.android.music.playstatechanged");
i.putExtra("position", Long.valueOf(123));
i.putExtra("playing", false);
sendStickyBroadcast(i);
}
}
I receive the pause event, when the button is pressed, through a mediabuttonintentreceiver and then execute the pause() function. Because i'm developing the app for gingerbread, the remotecontrolclient isn't available and the only relevant stuff to flag a playsate change in the music player app i found was:
Intent i = new Intent(what);
i.putExtra("id", Long.valueOf(getAudioId()));
i.putExtra("artist", getArtistName());
i.putExtra("album",getAlbumName());
i.putExtra("track", getTrackName());
i.putExtra("playing", isPlaying());
sendStickyBroadcast(i);
The audiofocus isn't lost when i pause the playback, because i receive no messages in the log from the onaudiochangelistener:
private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
String LOGTAG = "AUDIOFOCUSCHANGELISTENER";
switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS:
Log.e(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS, turning FM off");
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
Log.e(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
Log.e(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT");
break;
case AudioManager.AUDIOFOCUS_GAIN:
Log.e(LOGTAG, "AudioFocus: received AUDIOFOCUS_GAIN");
break;
default:
Log.e(LOGTAG, "Unknown audio focus change code " + focusChange);
}
}
};
What am i missing or isn't functioning properly?
I hope that someone can help me, because i've searched the forum, googled and have tested things for days now without success
EDIT: What i forget to mention, the functions/the code is running in a background service. Maybe it is helpfull.
EDIT
Ok, i've finally narrowed it down to a more specific point. This happens only if i start the mediaplayer in conjunction with the Intent.ACTION_SCREEN_OFF.
If i start the mediaplayer before that intent, for example in the onCreate() function of the service and then turn off the screen, turn it back on (lock screen), press the pause button, turn it off again and finally turn it on again, the media controls are visible and in pause state on the lock screen.
But if i start the mediaplayer after receiving the Intent.ACTION_SCREEN_OFF, then the above problem happens.
Can it have something to do with that, that i start the mediaplayer inside the braodcastreceiver-class, which is inside the service, when the problem happens? Or should you simply not start a mediaplayer after the screen has turned off although you have a wake lock?
I want to play a notification sound and my problem it that the sound loops forever, when it should sound only once.
I've tried two ways:
notification.sound = Uri.parse("content://media/internal/audio/media/38");
and
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
mMediaPlayer.setDataSource(this, Uri.parse("content://media/internal/audio/media/38"));
mMediaPlayer.setLooping(false);
mMediaPlayer.prepare();
mMediaPlayer.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
Log.v(Utils.TAG, "onprepared");
mp.start();
}
});
mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
Log.v(Utils.TAG, "end, we should release");
mp.stop();
mp.release();
}
});
In the second case, I never see the trace "end, we should release", the audio is played over and over and over again.
Any idea?
Thank you very much
UPDATE:
I've tried two devices and:
It loops forever on a Galaxy Nexus with ICS 4.0.4
It works fine on a HTC Hero 2.2.1
There are sounds with "built-in" loops which will play for ever. This is different to setting the MediaPlayer to looping. If you start playing a sound with a built-in loop, it will never finish. These are mostly ring tones (as opposed to alarm tones or notification tones). You can set the RingtoneManager to return only notification tones or alarm tones with myringtonemanager.setType(RingtoneManager.TYPE_ALARM|RingtoneManager.TYPE_NOTIFICATION)
which will exclude most looping sounds, but unfortunaley this is not guaranteed to exclude them all on any device. :-(
Therefore the solution of Tiago Almeida is a good work-around (and i've voted it up) though it will also truncate all sounds which have just a few (and no infinite) loops.
Try this:
try {
mp.setDataSource(uri.toString());
mp.setAudioStreamType(AudioManager.STREAM_ALARM);
mp.prepare();
mp.start();
mp.setOnSeekCompleteListener(new OnSeekCompleteListener() {
public void onSeekComplete(MediaPlayer mp) {
mp.stop();
mp.release();
}
});
} catch (Exception e) {
e.printStackTrace();
}
One more workaround for this problem
boolean soundPlayedOnce = true;
if(soundPlayedOnce){
mp.start();
soundPlayedOnce = false;
}
set this boolean to true right before you want to play sound