Sound effect on Android live wallpaper - android

Can Android live wallpaper create sound effects based on the touch of users?
I don't see alot of live wallpaper with sound effects out on the market. Is there a reason for it? For e.g, battery drain or other programming issues?

You can use a MediaPlayer in your WallpaperServiceClass.
You need to put the .mp3 or whatever sound resource you
want to use in your /res/raw folder.
public class MyWallpaperService extends WallpaperService {
private MediaPlayer mediaPlayer;
#Override
public void onCreate() {
super.onCreate();
mediaPlayer =
MediaPlayer.create(getApplicationContext(),
R.raw.your_sound);
}
// and in your WallpaperEngine SubClass start the sound on touch :
class MyWallpaperEngine extends Engine {
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
// touch is not activated on default so do it here :
setTouchEventsEnabled(true);
}
#Override
public void onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mediaPlayer.start();
}
}
}
To stop the sound use :
mediaPlayer.pause()
or when you're done kill the mediaPlayer with :
mediaPlayer.release();
Shouldn't drain unnecessary resources then since its only reacting on touch.

Related

Automatic ducking not working for text-to-speech (Android 8+)

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?

how to avoid overlapping sounds in libGdx?

hi I am using the sound class for my music so it will loop correctly (as advised here Libgdx: Lags in soundtrack looping) but when i close the app(it stills runs in the background) and open it again the sound starts to play over the previous sound, how can i avoid this?
This is my current music handler class
public class MusicHandler {
private Sound bgMusic;
public MusicHandler(Sound backgroundMusic){
bgMusic = backgroundMusic;
}
public void update(boolean play){
if(play){
bgMusic.loop();
}
else{
bgMusic.pause();
}
}
public void dispose(){
bgMusic.dispose();
}
}

Android Game : OnCompletionListener for the Music in Libgdx

I am playing a music in Libgdx game. I wish to have a listener like this to play the music and do a specific process after that. But the program control never reaches the onCompletionListerner part.
private void playMusic() {
gameMusic = Gdx.audio.newMusic(Gdx.files.internal("data/bgm.mp3"));
gameMusic.play();
gameMusic.setOnCompletionListener(Music.OnCompletionListener(){
#Override
public void onCompletion(Music aMusic){
actionResolver.getLeaderboardGPGS();
}
}
);
Just add new before Music.OnCompletionListener() and it should work.
gameMusic.setOnCompletionListener(new Music.OnCompletionListener() {
#Override
public void onCompletion(Music aMusic) {
actionResolver.getLeaderboardGPGS();
}
});
Since you're passing an object (that implements OnCompletionListener), it has to be created with new as always.

MediaPlayer gives different results if it has to wait longer before .start() is called

I'm trying to use a MediaPlayer instance to play several audio files individually, in response to various sensor events.
I've found that when I load up the clip to be played right before calling MediaPlayer.start(), the audio clip will play fine. However, the application takes a major performance hit. Ideally, each audio clip should be loaded into the MediaPlayer immediately after the last one was played, leaving the MediaPlayer ready to start playback the instant the SensorEvent comes in.
I would expect this to be simple, but now that I made the change the audio just doesn't play. PlayAudioClip() is definitely still being called as expected, but something is going wrong after that. No errors are thrown, so I don't think the MediaPlayer is changing state, but could something be interfering with in the time that it's waiting to play?
Here is a simplified version of my code:
public class MainActivity extends Activity implements SensorEventListener {
private Random numGenerator;
private SensorManager manager;
private Sensor accelerometer;
private MediaPlayer mediaPlayer;
private Uri[] audioClips;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initVariables();
prepareNextAudioClip(); //load first audioClip
}
#Override
public void onSensorChanged(SensorEvent event) {
if(conditionsRight()){
playAudioClip();
}
}
}
private void playAudioClip() {
mediaPlayer.start();
prepareNextAudioClip();
}
private void prepareNextAudioClip() {
try {
mediaPlayer.reset();
Uri audioClip = audioclips[(int) Math.floor(numGenerator.nextDouble()*audioClips.length)];
mediaPlayer.setDataSource(this, audioClip);
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
}
//Code below here isn't very important... handling setup and teardown
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
protected void onResume() {
super.onResume();
manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
}
private void initVariables() {
audioClips = new Uri[]{
Uri.parse("android.resource://com.example.afraidofflying/" + R.raw.audio1),
Uri.parse("android.resource://com.example.afraidofflying/" + R.raw.audio2),
Uri.parse("android.resource://com.example.afraidofflying/" + R.raw.audio3)
};
numGenerator = new Random();
mediaPlayer = new MediaPlayer();
manager = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if(null == accelerometer) finish();
}
protected void onPause() {
super.onPause();
manager.unregisterListener(this);
}
protected void onDestroy(){
mediaPlayer.release();
mediaPlayer = null;
}
}
PS: This has all been assuming I'll only use one instance of MediaPlayer but I'd also like input on if you think using multiple MediaPlayers and delegating each of them 1 audio clip would be advisable. My intuition is no because for my purposes I'd have to use 10-20 MediaPlayers, but it would be good to hear outside perspectives on it.
It's because you're resetting player right after starting playback.
private void playAudioClip() {
mediaPlayer.start(); //starting playback
prepareNextAudioClip(); //reset
}
if you want to play files in queue, than you can use one instance. But if you have to play several files simultaneusly, then you need to have several media player instances.
I think you have to look at subtle points regarding using Mediaplayer class
In your code you used:
initVariables();
prepareNextAudioClip(); //load first audioClip
initVariables() seems ok, Now lets see prepareNextAudioClip()
...
mediaPlayer.reset();
...
...
mediaPlayer.prepare();
The above code seems to corrupt Mediaplayer state machine. Please refer to http://developer.android.com/reference/android/media/MediaPlayer.html for details on using new, prepare,reset. It is better to write defensive MediaPlayer code using Errorlistener

which Media Player reached its end, and different set of orders on the onCompletion() method

Lets say I have several players I've created.
And Lets say that for each one of them, I want a different set on actions to be activated.
How can I locate which player has been finished (the implementation itself of the case sentence) in order to act differently for each player ?
For example: in order to handle a single player, all we have to do is to implement the onCompletion() method like this:
public void onCompletion(MediaPlayer mp){
//DO SOMETHING HERE THAT FITS FOR ALL KINDS OF PLAYER'S TYPE OBJECTS
}
How do I add a case sentence to expand it to handle several different player objects ?
Thanks !
The MediaPlayer attribute passed to this method is the same MediaPlayer that has just completed, so as long as you are keeping a pointer to each media player (such as through a global variable), then all you need to do is check which media player you have received:
public class MyClass implements OnClompleteListener
{
MediaPlayer player1, player2, player3;
//initialize them
player1.setOnCompleteListener(this);
player2.setOnCompleteListener(this);
player3.setOnCompleteListener(this);
#Override
public void onCompletion(MediaPlayer mp)
{
if (mp == player1)
{
//TODO handle player 1 completion
}
else if (mp == player2)
{
//TODO handle player 2 completion
}
else if (mp == player3)
{
//TODO handle player 3 completion
}
}
}
You can also handle this in-line, without implementing the OnCompleteListener:
player1.setOnCompleteListener(new OnCompleteListener() {
#Override
public void onCompletion(MediaPlayer mp)
{
//mp IS ALWAYS EQUAL TO player1!
}
});
You can either create a class that extends MediaPlayer and give it an attribute like a number to keep track of which player is which. Then you would check the player's number in the onCompletion() method. Otherwise, you could create different onCompletion listeners and set them to the different players.

Categories

Resources