I have a manager class with an array of MediaPlayer instances which is the manager for playing audio on my app. Until now, it worked perfectly in background and keep playing the audio when the device is blocked.
Now, starting with Oreo devices, the audio playing stops. Is there an easy way of forcing the device to keep alive the MediaPlayer instance which is playing the audio? I mean a simple way without using services or without creating custom bars on the notification bar of the device, which are the options I found for now here in Stack Overflow. Probably must be a simpler way.
This is the code I used to play an audio until now:
MediaPlayer mPlayer = new MediaPlayer();
AssetFileDescriptor fileDescriptor = ApplicationContextProvider.getContext().getAssets().openFd(res.getUrl());
long start = fileDescriptor.getStartOffset();
long end = fileDescriptor.getLength();
mPlayer.setDataSource(fileDescriptor.getFileDescriptor(), start, end);
mPlayer.prepareAsync();
mPlayer.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mPlayer.setLooping(loop);
fileDescriptor.close();
Use foreground Serive. For details on why the service will no longer work watch
https://www.youtube.com/watch?v=Pumf_4yjTMc
It clearly says that background services will be stopped. For tutorial on Foreground Services watch:
https://www.youtube.com/watch?v=FbpD5RZtbCc
Remember you would also need to learn the notification channels starting Oreo. This guy has introduced that too.
Related
I have used ringtonemanager previously in android studio and it seemed to lower the volume of any music that was playing in a different app to play the alert i was trying to play, then once my alert had completed the background music would then come back to normal volume (as the default alarm/notification would do) But now a year or so later im trying to implement this again but my alert cannot be heard over the music playing in Google Play Music.
Is this a change that now requires additional parameters to function as it used to?
Im using:
Uri notification =
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
myRM = RingtoneManager.getRingtone(this.getContext(), notification);
myRM.play();
Many Thanks
Handling Changes in Audio Output seems what fits your need.
In short, you need to request audio focus before starting playing.
...
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(null, mStreamType, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
mRingtone.play();
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
Used to indicate a temporary request of audio focus, anticipated to
last a short amount of time, and where it is acceptable for other
audio applications to keep playing after having lowered their output
level (also referred to as "ducking").
Remember to release audio focus when finishing..
if (mRingtone != null && mRingtone.isPlaying()) {
mRingtone.stop();
}
mRingtone = null;
if (mAudioManager != null) {
mAudioManager.abandonAudioFocus(null);
}
My app is a music pad, which allows the user to create their own music by pressing buttons that will play a specific sound, and if the users presses more than one button there will be more sounds being played at the same time.
I want to stop all sounds when the onPause() gets called. But I realized that if I have more than one sound being played by the same Media player Object it only stops the last sound that was attributed to it, and the others stay on playing.
It would be very unpleasant for the user to receive a call and having my app sounds still on playing :p
Any help would be appreciated.
#Override
protected void onPause() {
super.onPause();
try {
while (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}catch (IllegalStateException e){
//Do nothing
}
}
EDIT
I tried to implement SoundPool API but since my app is very dynamic (users can upload their samples and also record using mic). And I have everything already implemented and working well, it would be a mess to change it now to another API rather than MediaPlayer. Is there any way to stop all sounds that were attributed to the MediaPlayer object and that are currently being played? maybe accessing to some other classes and using other methods to stop all the sounds?
I would suggest you look into the SoundPool API. It looks like that would be well suited for your task. It allows you to preload sound files and play them independently.
The SoundPool class manages and plays audio resources for applications.
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.
After a few research and trial and error there is no way that I discovered to stop all sounds being played by the same MediaPlayer Object, you can only control the last sound being attributed to it, all the other will continue until they end or the app gets destroyed.
Ok so what I did was:
I created an object for each key sound of my music pad, and Override the onPause() with the following code:
#Override
protected void onPause() {
super.onPause();
if (mAudioManager.isMusicActive()){
for (MediaPlayer aMMediaPlayer : mMediaPlayer) {
if (aMMediaPlayer != null) {
try {
if (aMMediaPlayer.isPlaying()) {
aMMediaPlayer.stop();
aMMediaPlayer.release();
}
} catch (IllegalStateException e) {
//Do nothing
}
}
}
}
}
I am created an Android app thta needs to have a fullscreen seemless video loop playing in the background. By 'in the background' I mean that there will be buttons on top of the video.
I've read these threadw already
playback video full screen
Integrating video file in android app as app background
but I'm still confused about the following
1 Is the mediaplayer needed for video playback?
2 Will using OnCompletionListener create a 'seamless' loop or will there be a 'hiccup' as the video loops?
Use the setOnPreparedListener to tell the MediaPlayer to loop and start
videoview.setOnPreparedListener(new OnPreparedListener()
{
#Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
mp.start();
}
});
This is seemless on some devices, but can cause a frame or two of stutter on others :/
Such Problem: I have video file recorded with two sound channels. I tried to switch off left sound channel by this code:
MediaPlayer mp;
....
mp.setVolume(0.f, 1f);
... and on Tablet this work good (right volume channel sounds well). But then I tried it on googleTv which I connect to Samsung UE46ES6307U and this code did not work, sound swichs off.
Maybe it is bounds to Dolby Digital Plus / Dolby Pulse audio? Can I somehow programmatically discover how sound channels device has, and what volume in each chanels setuped?
Update:
On this forum http://www.googletvforum.org/forum/logitech-revue/375-audio-problems-logitech-revue.html in one of replies such message: "Logitech has not yet figured out how to pipe multichannel audio thru hdmi.you have to use the optical output. Which is ok."
"How are you constructing the MediaPlayer?"
Videoview vv;
...............
vv.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setVolume(0.f, 1f);
}
});
Update:
public class MainActivity extends Activity {
MediaPlayer mp = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (mp != null) {
mp.reset();
mp.release();
}
mp = MediaPlayer.create(this, R.raw.test);
mp.start();
}
public void onTurnOffLeft(View v){
mp.setVolume(0.f, 1.f);
}
public void onTurnOffRight(View v){
mp.setVolume(1.f, 0.f);
}
}
Method onTurnOffLeft switchs off all sound, and onTurnOffRight method has no effect.
Update2
I tried to play .ogg audio file codded with Vorbis codec - channels turns off well. But I tried to play video files codded with mp3, ac3, pcm, aac - and problem with turning off channels is still there... I need to turn off audio channels in video, but how to solve that problem, I do not know yet.
The MediaPlayer object is backed by different libraries across the devices (not the same between a tablet and a Google TV). How are you constructing the MediaPlayer?
One thing you may want to try is calling #reset() on the MediaPlayer right after it is constructed. By default when you use a "new" operator to construct a MediaPlayer instance it is in an IDLE state (at least on Google TV). By calling reset you allow your own OnErrorListener.onError() handler to be invoked. This will let you see if there is some underlying error that is not visible otherwise.
You may also want to look at AudioManager#setStreamVolume(int, int, int) which sets the volume of ALL streams of a particular type.
Edit 1:
Since you are just grabbing the VideoView from layout (I'm guessing since that code was omitted) after you setup the listener you should call reset on the video view.
I have to play sounds on GUI events, like clicking buttons etc. For this purpose, I call the following native code from WebView:
MediaPlayer _SoundPlayer = new MediaPlayer();
private void playSound(String sound)
{
_SoundPlayer.reset();
try
{
AssetFileDescriptor afd = getAssets().openFd("sound/" + sound + ".mp3");
_SoundPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
_SoundPlayer.prepare();
_SoundPlayer.start();
}
catch (Exception e) { }
}
The problem is there is a delay ~500ms between an event and its sound. Can I optimize playing sound somehow, maybe, creating a dedicated MediaPlayer instances for every kind of sound?
Regards,
Use SoundPool for low-latency media playback, instead of MediaPlayer.
I see that this already has an accepted answer, but I would add that there is no complete solution at this time: Android currently has very large audio latency. Devs are still waiting for a good solution.
This issue refers to the NDK, but the issue is general:
http://code.google.com/p/android/issues/detail?id=3434