Android : Not able to stop the audio from the same button - android

I'm working on an app in which there is a grid layout with 8 buttons and each attached to a sound. Now I'm able to play the audio on the click of a button but when I press the same button again the audio doesn't stop.
All my buttons are attached to a common onClick method and the class file retrieves the id of the button and matches with the sound file present in the raw folder.
I'm using a flag for this but don't know where I'm going wrong.
My Code
boolean play = true;
MediaPlayer mediaPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void buttonTapped(View view)
{
int id = view.getId();
String ourID = "";
ourID = view.getResources().getResourceEntryName(id);
int resourceID = getResources().getIdentifier(ourID, "raw", "com.starprojects.gridlayoutdemo");
mediaPlayer = MediaPlayer.create(this,resourceID);
if(play)
{
mediaPlayer.start();
play = false;
}
else {
// mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
// play = true;
}
// mediaPlayer = null;
Log.i("button tapped",ourID);
}
}

define mediaPlayer outsite of function, then do that
public void buttonTapped(View view) {
int id = view.getId();
String ourID = "";
ourID = view.getResources().getResourceEntryName(id);
int resourceID = getResources().getIdentifier(ourID, "raw", "com.starprojects.gridlayoutdemo");
stopPlayer();
mediaPlayer = MediaPlayer.create(this,resourceID);
if (mediaPlayer != null)
mediaPlayer .start();
}
public void stopPlayer() {
if (mediaPlayer != null) {
mediaPlayer .stop();
mediaPlayer .release();
}
mediaPlayer = null;
}
thats all :)

This may or may not be related to your problem, but don't forget to call
mediaPlayer.release();
mediaPlayer = null;
when you are finished. If you do not, resources get built up and start affecting sound outside of the app. Keep in mind a new MediaPlayer is being allocated every time you press the button. I have done this in a previous app and the sound stopped working after a few minutes.
Let me know if this changes anything.
As a matter of fact, you can try making your MediaPlayer a member of the class (defined outside the function) since you only need one sound playing at once. If it isn't null or .isPlaying(), release it. Otherwise, create and play.

Related

Null Pointer Exception when calling mediaPlayer.start() : Android

Basically what I want is to allow the user to select a audio file from their device and once they do, this activity starts and the music/audio file will be played. For that I've used included an intent-filter in my Android Manifest File, and its working fine, there are no errors.
The problem is when I call mediaPlayer.start() I get a Null Pointer Exception. From what I've read so far, this happens because MediaPlayer fails to create a object or something... the MediaPlayer.cretae() returns null.
The following is the whole code for this Activity:
public class IntentPlayerActivity extends AppCompatActivity {
TextView song_name,artist_name;
ImageView playPauseBtn;
SeekBar seekBar;
static Uri uri;
static MediaPlayer mediaPlayer = new MediaPlayer();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_player);
initViews();
Intent intent = getIntent();
if (intent.getAction().equals(Intent.ACTION_VIEW)){
Log.d("Intent Player_Activity:", " File Path: "+ intent.getData().getPath());
playPauseBtn.setImageResource(R.drawable.ic_pause_circle_outline);
uri = Uri.parse(intent.getData().getPath());
Log.d("Intent Player_Activity:", " URI: "+uri.toString());
if (mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = MediaPlayer.create(getApplicationContext(),uri);
mediaPlayer.start();
}else {
mediaPlayer = MediaPlayer.create(getApplicationContext(),uri);
mediaPlayer.start();
}
}
}
private void initViews() {
song_name = findViewById(R.id.song_name);
artist_name = findViewById(R.id.song_artist);
playPauseBtn = findViewById(R.id.play_pause);
seekBar = findViewById(R.id.seekBar);
}
}
I'm hopping someone could explain what MediaPlayer.create() dose and what could be causing it to fail, for my case I don't believe the audio file is an invalid format or the specified media file cannot be found. I think its something else.
Delete:
uri = Uri.parse(intent.getData().getPath());
Instead, pass intent.getData() to MediaPlayer.create():
mediaPlayer = MediaPlayer.create(getApplicationContext(),intent.getData());

MediaPlayer pause called in state 8

I am trying to implement a RecyclerView with audio messages and playing those audio files. Previously I was stuck on a problem when I was changing play and pause image on ImageButton, so I found this solution and changed my code accordingly. But now I am facing another issue. Whenever I play the audio , the image changes to pause and when I click this button again, it gives me an error: pause called in state 8. I know what is causing the problem, but cannot figure out the solution.
Here is my onBindViewHolder :
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((MyChatMediaViewHolder) holder).bindData(mChats.get(position), position);
}
Here is my MyChatMediaViewHolder class :
private class MyChatMediaViewHolder extends RecyclerView.ViewHolder {
private TextView txtUserAlphabet, timer;
private ImageView play;
private SeekBar seekBar;
ProgressBar progressBar;
RelativeLayout media_chat;
Chat chat = null;
public MyChatMediaViewHolder(View itemView) {
super(itemView);
play = (ImageView) itemView.findViewById(R.id.play);
seekBar = (SeekBar) itemView.findViewById(R.id.seekbar);
txtUserAlphabet = (TextView) itemView.findViewById(R.id.text_view_user_alphabet);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressUpdate);
media_chat = (RelativeLayout) itemView.findViewById(R.id.chat_media);
timer = (TextView) itemView.findViewById(R.id.timer);
Log.e("TAG111", "bindData: ");
play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
isPlay = !isPlay;
//Handling for background selection state changed
int previousSelectState=mSelectedItemPosition;
mSelectedItemPosition = getAdapterPosition();
//notify previous selected item
notifyItemChanged(previousSelectState);
//notify new selected Item
notifyItemChanged(mSelectedItemPosition);
}
});
}
public void bindData(Chat chat, int currentPosition) {
this.chat = chat;
MediaPlayer mediaPlayer = new MediaPlayer();
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
try {
mediaPlayer.setDataSource(chat.mediaUrlLocal);
metaRetriever.setDataSource(chat.mediaUrlLocal);
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
String duration =
metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long dur = Long.parseLong(duration);
String seconds = String.valueOf((dur % 60000) / 1000);
String minutes = String.valueOf(dur / 60000);
String out = minutes + ":" + seconds;
timer.setText(out);
if(currentPosition == mSelectedItemPosition) {
Log.e("pause", "bindData: " + mediaPlayer.isPlaying());
if(isPlay) {
mediaPlayer.start();
play.setImageResource(android.R.drawable.ic_media_pause);
} else {
mediaPlayer.pause();
play.setImageResource(android.R.drawable.ic_media_play);
}
} else {
play.setImageResource(android.R.drawable.ic_media_play);
}
}
}
The problem here I think is : new MediaPlayer instance gets created every time
play button is clicked, so when I try to pause , a new media player is again created which was never started.
So the question is : Where should I create the new MediaPlayer instance?
First of all your RecyclerView.Adapter's purpose is to inflate your view, you shouldn't write your business logic here.
Second you should use only one instance of media player. You should initialize your media player inside your Activity or Fragment.
Create an interface implement in your Activity or Fragment and pass its reference to your adapter. Whenever you want to play audio you will use your interface to delegate your audio file path or stream to Activity or Fragment, reset or release your media player and play your audio.
I think the best solution (if you need to play only one audio at a time) would be to keep only one instance of MediaPlayer in RecyclerView.Adapter and also you can keep there a map where the key is position and value would be simple class containing: flag - isPlaying, duration (when you played your song and paused it, you wouldn't like to start it from beginning but from where you paused it), etc. So when you are scrolling up and down you will be able to retain state of views that were played/paused.

Hello. I'm making a lyrics app which can also play the music of the lyrics

what I'm trying to do is add 1 button that will play and stop the music. is it possible to loop them like 1st click play then 2nd click stop 3rd click will start from beginning and 4th stops again and so on?
based on my search on google it's something like this? sorry if noob question
public void playtd(View view) {
if(!td.isPlaying()) {
td.start();
}
else if(td.isPlaying()) {
td.pause();
}
}
Try This:
MediaPlayer td;
boolean isPrepared;
public void prepareMediaPlayer(Uri yourTrackUri){
// call this on initialization of your mediaplayer
sMRMediaPlayer = MediaPlayer.create(mContext, uri);
sPrepared = true;
}
public void playtd(View view) {
if (!isPrepared) {
prepareMediaPlayer(Uri yourTrackUri)
}
if(!td.isPlaying()) {
td.start();
else {
// reprepare mediaplayer
td = MediaPlayer.create(Context, uriToUrFile);
isPrepared = true;
}
} else { // stop playing instead of pause, stop will start playing next time u play from beginning
td.stop();
}
void releaseMediaPlayer() {
if (td!= null) {
Log.d(TAG, "MediaPlayer is released.");
td.reset();
td.release();
td= null;
isPrepared = false;
}
}
call releaseMediaPlayer once done with all play and stop stuff (may be on destroy etc.)
initialize mediaplayer by passing track uri to prepareMediaPlayer
add try catch, wherever needed

Android button soundboard

I'm trying to make a soundboard app, but I'm running into a problem with handling the sound files. More specifically I do not know how to get it so when a button is pressed it plays a corresponding sound back.
I've tried using this way
Play sound on button click android
I tried implementing a media player for each sound file and button but the app crashes on start up.
I have 10 buttons with 10 corresponding sound files that are located in the raw file in src/res/raw/
Any idea on how to make it work?
//this is a breaking bad soundboard app, so please excuse the language. Sorry if you find it offensive
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
whatup = (Button)this.findViewById(R.id.button);
haveatit = (Button)this.findViewById(R.id.button2);
hello = (Button)this.findViewById(R.id.button3);
whining = (Button)this.findViewById(R.id.button7);
money = (Button)this.findViewById(R.id.button4);
yeah= (Button)this.findViewById(R.id.button8);
miserable = (Button)this.findViewById(R.id.button5);
mother = (Button)this.findViewById(R.id.button9);
gatorade = (Button)this.findViewById(R.id.button6);
science = (Button)this.findViewById(R.id.button10);
whatup.setOnClickListener(this);
haveatit.setOnClickListener(this);
hello.setOnClickListener(this);
whining.setOnClickListener(this);
money.setOnClickListener(this);
yeah.setOnClickListener(this);
miserable.setOnClickListener(this);
mother.setOnClickListener(this);
gatorade.setOnClickListener(this);
science.setOnClickListener(this);
WhatUp = MediaPlayer.create(MainActivity.this, R.raw.whatupb);
HaveAtIt = MediaPlayer.create(MainActivity.this, R.raw.haveatit);
Hello = MediaPlayer.create(MainActivity.this, R.raw.hello);
Whining = MediaPlayer.create(MainActivity.this, R.raw.stopwhining);
Money = MediaPlayer.create(MainActivity.this, R.raw.wheresmymoney);
Yeah = MediaPlayer.create(MainActivity.this, R.raw.yeahb);
Miserable = MediaPlayer.create(MainActivity.this, R.raw.miserableb);
Mother = MediaPlayer.create(MainActivity.this, R.raw.motherofgod);
Gatorade = MediaPlayer.create(MainActivity.this, R.raw.gatorade);
Science = MediaPlayer.create(MainActivity.this, R.raw.yeahscience);
}
this is for handling when the button is pressed. Obviously there needs to be more, but I was just testing 1 button and it crashes when I try starting it.
#Override
public void onClick(View view) {
if(view==whatup)
{
WhatUp.start();
}
}
Log Cat Errors:
http://imgur.com/ZWYsLl7
I assume your sounds might be sound_1, sound_2, sound_3, etc. and your buttons are button_1, button_2 and so on..
You should create a loop to get the ids in onCreate method:
for (int i = 0; i < 10; i++) {
// get the id for buttons
int btnId = getResources().getIdentifier("button_"+i, "id", getPackageName());
// get the res for sounds
int rawId = getResources().getIdentifier("sound_"+i, "raw", getPackageName());
// set a click listener to all your buttons
button[i] = (Button) findViewById(id);
button[i].setOnClickListener(new OnClickListener() {
public void onClick(View view) {
// create the media player with the raw id
mp = MediaPlayer.create(MainActivity.this, rawId);
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
// avoid NullPointerException see the links below
mp.release();
}
});
// play the sound
mp.start();
}
});
}
Read the topic reference: Using MediaPlayer. You could also get identifer with the context: How to dynamically generate the raw resource identifier in android? and this might help you for explanation of release() method: Play sound on button click - Null pointer exception and read the Releasing the MediaPlayer part from Using MediaPlayer. I'm not sure but it should do the trick..
Good luck.
UPDATE
Change this check if(view==whatup) to if(view.getId() == R.id.button).
In onClick method you need to check the id regarding the view, with getId() method.

How do I play an mp3 in the res/raw folder of my android app?

I have a small (200kb) mp3 in the res/raw folder of my android app. I am trying to run it in an emulator from Eclipse. It is recognized as a resource in the R file but when I try to prepare/start, my activity crashes! Was there something else I needed to change, perhaps in the manifest?
MediaPlayer mPlayer = MediaPlayer.create(FakeCallScreen.this, R.raw.mysoundfile);
try {
mPlayer.prepare();
mPlayer.start();
} catch (IOException e) {
// handle this later
}
When starting the activity i.e on onCreate put the following code.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MediaPlayer mPlayer = MediaPlayer.create(FakeCallScreen.this, R.raw.mysoundfile);
mPlayer.start();
}
When stopping the activity i.e on onDestroy put the following code.
public void onDestroy() {
mPlayer.stop();
super.onDestroy();
}
Hope it helps :)
You'll likely prefer to use the SoundPool class. It reduces latency when it's time to play the sound, and offers other niceties like being able to prioritise sounds when there are too many to play at once.
From the docs:
A SoundPool is a collection of samples that can be loaded into memory from a resource inside the APK or from a file in the file system. The SoundPool library uses the MediaPlayer service to decode the audio into a raw 16-bit PCM mono or stereo stream. This allows applications to ship with compressed streams without having to suffer the CPU load and latency of decompressing during playback.
For example:
/**
* How many sounds can be played at once.
*/
private static final int MAX_SOUND_POOL_STREAMS = 4;
/**
* Modify this as part of your own priority scheme. Higher numbers mean higher
* priority. If you don't care, it's okay to use the same priority for every
* sound.
*/
private static final int NORMAL_PRIORITY = 10;
private int mySoundId;
#Override
public void setupContent() {
this.soundPool = new SoundPool(MAX_SOUND_POOL_STREAMS,
AudioManager.STREAM_MUSIC, 100);
this.mySoundId = this.soundPool.load(this.getApplicationContext(),
R.raw.mySound, 1);
}
#Override
private void playMySound() {
this.soundPool.play(this.mySoundId, 1, 1, NORMAL_PRIORITY, 0, 1);
}
this is a static method I use in my projects.
I add it to my Utils class:
public static void playSound(final Context context, final SoundType type)
{
new Thread(new Runnable()
{
#Override
public void run()
{
MediaPlayer mediaPlayer = new MediaPlayer();
int resId = -1;
switch (type)
{
case INCOMING_NOTIFICATION:
resId=R.raw.noti_sound;
break;
case SEND_BETTING_SLIP:
resId=R.raw.slip_sent;
break;
case TRIVIA_RIGHT_ANSWER:
resId=R.raw.game_bonus;
break;
case TRIVIA_WRONG_ANSWER:
resId=R.raw.whistle_referee_trivia_bad_answer;
break;
}
if (resId != -1)
{
mediaPlayer = MediaPlayer.create(context, resId);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(false);
mediaPlayer.start();
while (mediaPlayer.isPlaying() == true)
{
}
}
}
}).start();
}
}
now I defind an Enum (SoundType) and placed the mp3 files in raw folder under
res folder.

Categories

Resources