I've built a small app that mutes/unmute the music stream using the class AudioManager.
In fact, it works until I close the application. i.e. I've muted the sream, I close the app, I restart the app and the button doesn't unmute the stream any more. I've searched in the net but no one seems to have met this problem.
Here's my code:
public class ControlloVolume extends Activity {
ToggleButton tb_mute;
Button btn_mute;
AudioManager mAudioManager;
boolean mute;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_controllo_volume);
tb_mute = (ToggleButton) findViewById(R.id.tb_mute);
btn_mute = (Button) findViewById(R.id.btn_mute);
mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
if(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)==0){
mute = true;
tb_mute.setChecked(mute);
}else{
mute = false;
tb_mute.setChecked(mute);
}
}
public void onButtonClicked(View view){
if(!mute){
mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
tb_mute.setChecked(true);
mute = true;
}else{
mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, false);
tb_mute.setChecked(false);
mute = false;
}
}
First, beware it's not recommended
For a better user experience, applications MUST unmute a muted stream
in onPause() and mute it again in onResume() if appropriate.
But I assume you know what you're doing, so here we go.
Note this line from the docs on setStreamMute
The mute command is protected against client process death: if a
process with an active mute request on a stream dies, this stream will
be unmuted automatically.
I've checked on my device and indeed, when I just exit my activity, stream stays muted. But as soon as I kill the process, mute goes away.
Take a look at activity lifecycle.
As your current approach will not work reliably, you could write a foreground service which will trigger the mute - start that service from your activity.
Also you would likely need to setStreamSolo.
Two important things.
Volume==0 and muted are NOT the same thing. I.e. stream can have volume==0 but be not muted. Though if stream is muted, volume will always be 0
mute requests are cumulative. I.e. if you've set mute twice, you must unmute twice as well - your code doesn't handle that
As a side note, for such app you would probably want to use widget instead of activity.
Off topic. It seems surprisingly lot of people don't quite get how booleans work.
And as I see code such as yours regulary, here is a bit streamlined rewrite.
#Override
public void onCreate(Bundle savedInstanceState) {
// ... setup just like you did
// boolean is just like any other type. You can assign not only
// constants, but expressions too
mute = (mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)==0);
tb_mute.setChecked(mute);
}
public void onButtonClicked(View view){
mute = !mute; // invert value
mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, mute);
tb_mute.setChecked(mute);
}
Related
As described in documentation, the automatic ducking feature has been introduced in Android 8.0. Ducking means that if your music application has been interrupted by some short sound (like a notification, for ex.), your application will continue playing music, but music volume will be temporary lowered while short sound is playing.
I use a text-to-speech engine to read long articles, and want it to behave similar to music player, i.e. I want it to be automatically ducked by the system in android 8.0
I've got ducking to work fine without any additional code on Android 8.0 for music playing, but not for text-to-speech playing.
Here is a sample code
public class PlayerService extends Service {
//private MediaPlayer mp;
TextToSpeech tts;
#Override
public void onCreate() {
super.onCreate();
//...
//create foreground notification stuff omitted...
//...
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
am.requestAudioFocus(listener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
/*
mp = MediaPlayer.create(this, R.raw.music);
mp.setLooping(true);
mp.start();
*/
tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.setAudioAttributes(
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
);
}
tts.speak("IF you happen to have read another book about Christopher Robin, you may remember that he once had a swan (or the swan had Christopher Robin, I don't know which) and that he used to call this swan Pooh. That was a long time ago, and when we said good-bye, we took the name with us, as we didn't think the swan would want it any more. Well, when Edward Bear said that he would like an exciting name all to himself, Christopher Robin said at once, without stopping to think, that he was Winnie-the-Pooh. And he was. So, as I have explained the Pooh part, I will now explain the rest of it. ",
TextToSpeech.QUEUE_ADD, null);
}
});
}
#Override
public void onDestroy() {
tts.stop();
/*
mp.stop();
mp.release();
*/
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
am.abandonAudioFocus(listener);
super.onDestroy();
}
private AudioManager.OnAudioFocusChangeListener listener = new AudioManager.OnAudioFocusChangeListener() {
#Override
public void onAudioFocusChange(int focusChange) {
//nothing to do here
}
};
}
If I'd remove text-to-speech stuff and uncomment MediaPlayer lines, ducking will work fine for music playing. But if using text-to-speech as presented, no ducking is happening - during the notification sound text-to-speech continues playing as usually, and no volume change is performed.
I want ducking (volume change) to happen also if I use text-to-speech. What am I doing wrong?
Bit of a strange one this and I can't work out what's happening.
When I launch my app (a game) the music starts playing. I have a button which turns the music on and off. The settings are saved to shared prefs so they are retained.
All works well, you can press the home key, re-invoke the app, leave it in the background while doing other things etc. However, if the app is left in the background for a while (say, overnight), and then re-invoked. Everything works apart from the music.
You can go into the main menu, hit the 'music on/off' button multiple times, but get nothing.
The only way to start the music is to kill the app (or exit correctly, ie, press the 'back' key from the main menu) and then relaunch it so everything is re-created from scratch.
I've confirmed that the 'music' object is still valid and the 'music on/off' button presses are being registered.
Has anyone has similar issues with Media Player? I can't work out what I am (or am not doing) to cause this.
Code
This is my media player class:
public class MusicMan implements MediaPlayer.OnPreparedListener {
MediaPlayer musicPlayer;
MusicMan(Context myContext){
musicPlayer = MediaPlayer.create(myContext, R.raw.music);
musicPlayer.setVolume(.6f, .6f);
}
public void listener(){};
public void start(){
musicPlayer.setLooping(true);
musicPlayer.start();
}
public void stop(){
musicPlayer.stop();
}
public void pause(){
musicPlayer.pause();
}
public int getPos(){
return musicPlayer.getCurrentPosition();
}
public void skipTo(int position){
musicPlayer.seekTo(position);
}
#Override
public void onPrepared(MediaPlayer arg0) {
}
}
And then I simply crate an object like so:
MusicMan music = new MusicMan(view.getContext());
And then I just start and stop the music using the methods in the MusicMan class:
music.start();
You need to use
musicPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
Use this where you set new MediaPlayer player. It sets the wake lock to MediaPlayer and don't let CPU go sleep till you yourself didn't kill or stop application.
I am trying to play a background sound which runs throughout the application. Here I have 3 activities and the sound is started when the MAIN activity launches.
I want to achieve these:
1) play the bg sound continuously throughout the app whatever activity loads.
2) Switch off the sound when user clicks sound off button.
3) Stop the sound when the app closes.
So far I have tried this code to start the sound but it keeps on playing even if the app is closed.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioPlayer();
}
boolean isPlayingSound = true;
public void onClickSound(View view) {
final Button btn1 = (Button) findViewById(R.id.button3);
if(isPlayingSound){
btn1.setBackgroundResource(R.drawable.sound00);
isPlayingSound=false;
audioPlayer(false);/*Sound doesn't stops here*/
}
else{
btn1.setBackgroundResource(R.drawable.sound11);
isPlayingSound=true;
audioPlayer(true);
}
}
public void audioPlayer(boolean status){
MediaPlayer mp = MediaPlayer.create(this, R.raw.bg);
if(status) {
mp.start();
}
else {
mp.stop();
}
}
Can anyone plz have a look and help me out here. Thanks for help!!
you can playback the audio move to Service. you can reference ASOP music code
or look
Binding to a Started Service
As discussed in the Services document, you can create a service that is both started and bound. That is, the service can be started by calling startService(), which allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService().
If you do allow your service to be started and bound, then when the service has been started, the system does not destroy the service when all clients unbind. Instead, you must explicitly stop the service, by calling stopSelf() or stopService().
I'm playing around with Android to learn the API and I'm trying to code an activity which can listen for changes in audio events. For example, the activity I created plays a random ringtone when you press a button. The button displays a text saying "Random Ringtone", but when you press the button it says "Stop" and pressing it will, of course, stop playing the ringtone.
However, the problem is that when the ringtone stops playing on its own, the button still says "stop".
I've looked around to try to find an event listener that could listen for when the ringtone stops playing, but I can't seem to find one. I've seen some info out there about creating your own listeners, but I'm not interested in doing that (a little advanced for me right now).
Does an event listener of this type exist?
I may be wrong but I think the only audio class which raises an event when it finishes playing is the MediaPlayer class. Something like this should work...
public class MyActivity extends Activity
implements MediaPlayer.OnCompletionListener {
MediaPlayer player = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
player = new MediaPlayer();
player.setOnCompletionListener(this);
...
}
#Override
public void onCompletion(MediaPlayer mp) {
// Called when playback is complete
...
}
}
I am using VideoView to play an mp4 video. I would like to give the user the option of watching this video with sound or mute the sound if he/she chooses. I do not use the mediaController allowing the user to stop and play, I have "touch" events controlling this.
UPDATE: I have a menu that I have added a "mute" icon to. Now I am trying to figure out how to add the mute to this button. I am reading some info on from the Android AudioManager, in particular the setStreamMute. Here is what the API's say:
public void setStreamMute (int streamType, boolean state)
Since: API Level 1
Mute or unmute an audio stream.
The mute command is protected against client process death: if a process with an active mute request on a stream dies, this stream will be unmuted automatically.
The mute requests for a given stream are cumulative: the AudioManager can receive several mute requests from one or more clients and the stream will be unmuted only when the same number of unmute requests are received.
For a better user experience, applications MUST unmute a muted stream in onPause() and mute is again in onResume() if appropriate.
This method should only be used by applications that replace the platform-wide management of audio settings or the main telephony application.
Parameters
streamType The stream to be muted/unmuted.
state The required mute state: true for mute ON, false for mute OFF
Use the AudioManager service to mute and unmute just the stream related to your video. From the method(s) you have declared to respond to the user touch events, call methods like:
public void mute() {
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
am.setStreamMute(AudioManager.STREAM_MUSIC, true);
}
public void unmute() {
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
am.setStreamMute(AudioManager.STREAM_MUSIC, false);
}
This will leave the other streams (notification, alarm, etc.) active so you aren't silencing the whole device just to mute the video.
Also, if you need to suggest to your Activity which stream it should be pushing the audio through you can call Activity.setVolumeControlStream(AudioManager.STREAM_MUSIC) to tie your Activity's window to that stream.
I was able to implement my desire to have a mute button contained in a menu button. Each time the user interacts with the button, the video either mutes or unmutes. Here is the code:
private AudioManager mAm;
private boolean mIsMute;
// Audio mgr
mAm = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
mIsMute = false;
public void isMute() {
if(mIsMute){
mAm.setStreamMute(AudioManager.STREAM_MUSIC, false);
mIsMute = false;
}else{
mAm.setStreamMute(AudioManager.STREAM_MUSIC, true);
mIsMute = true;
}
}
And then inside my case:
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
// Mute
case R.id.main_menu_mute:
isMute();
break;
.........
}
return super.onOptionsItemSelected(item);
}