I want to know, how to run a song in a service, I also want to use .aidl file to expose clients the interface.
Sound basic for Android..
I recommended you for go through this tutorial MusicDroid - Audio Player Part.
There are three parts of these tutorial. Its nicely describe for how to implement Audio player for android using service and AIDL.
Also look at this android developer tutorial Media Playback.
I think this will help you a lot..!
I assume you know how to create a service, I did something before similar
import android.media.MediaPlayer;
private MediaPlayer mMediaPlayer;
private void play() {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(getSongUrl());
mMediaPlayer.prepare();
mMediaPlayer.start();
}
when interact with UI, send Intent from the UI to the service so that you can do let pause:
mMediaPlayer.pause();
or seek to certain time:
mMediaPlayer.seekTo((int) (to * mMediaPlayer.getDuration()));
and remember make sure call the release()
Please check the class here: http://developer.android.com/reference/android/media/MediaPlayer.html
Related
I've been playing some mp4 videos through the VideoView, which apparently uses/is a wrapper for the MediaPlayer.
As usual I see the typical ones in the logcat:
I/MediaPlayer﹕ Info (701,0)
I/MediaPlayer﹕ Info (702,0)
But then I see that one as well:
I/MediaPlayer﹕ Info (950,0)
As stated in this answer and others questions, most 9XX MediaPlayer Info/Warning/Error codes aren't officially documented in the SDK docs, but probably is related with "timed text tracks" (subtitles), since the only references to 9XX are MEDIA_INFO_UNSUPPORTED_SUBTITLE (901) and MEDIA_INFO_SUBTITLE_TIMED_OUT (902).
The thing is, I don't use any subtitles or external/extra resources while playing the video, so that would be strange.
Does anyone know any additional information about the 950 or the 9XX codes?
(I'm trying to track a bug that could be related to that since it's the last info I have going in the logcat - just exploring all the possibilities.)
Am facing the same warning but with a different scenario. In the following code, resetting the mediaplayer after onCompletion generates this warning. After it I have problems with the track and trying to restart it.
soundMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.reset();
mediaPlayer = MediaPlayer.create(MainActivity.this, soundUri);
mediaPlayer.start();
}
});
Hope it gives you a clue.
I want to implement a cool effect, when there is an explosion the music gets slightly slower for a moment.
The Music class of libgdx doesn't allow changing the pitch of the sound, I tried using the Sound class instead of the Music to play my music but its very slow at loading the files ( 5 sec for a 5 mb file, on Desktop! ).
So, the question is if there is a way to workaround this, or if there is an external library, that works both on desktop and android and can work along with libgdx.
After some searching I found a way by editing the libgdx source code.
You need to use the AudioDevice object to play your music sample by sample ,to do that you need to include the audio-extension of libgdx.
We gonna edit the libgdx source code so you need to download it and replace the gdx.jar , gdx-backend-android.jar and gdx-backend-lwjgl.jar with the correct libgdx projects(they have the same name without the jar extension)
1)Edit the AudioDevice.java inside com.badlogic.gdx.audio package of the gdx project
add the following code inside the interface
public void setSpeed(float val);
2)Edit the AndroidAudioDevice.java inside com.badlogic.gdx.backends.android package of the gdx-backend-android project
The Android side of the AudioDevice class relies on the AudioTrack class of the Android sdk ,this class has a setPlaybackRate(..) method.
add the following code inside the class
#Override
public void setSpeed (float speed) {
track.setPlaybackRate((int)(track.getSampleRate()*speed));
}
3)Edit the OpenALAudioDevice.java inside com.badlogic.gdx.backends.lwjgl.audio package of the gdx-backend-lwjgl project
The Desktop side of the AudioDevice relies on OpenAL (the opengl of audio) which has a handy set pitch method
add the following inside the class
#Override
public void setSpeed (float speed) {
alSourcef(sourceID, AL_PITCH, speed);
}
4)Play the audio
Here is the code for loading and playing the sound file
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.AudioDevice;
import com.badlogic.gdx.audio.io.Mpg123Decoder;
import com.badlogic.gdx.files.FileHandle;
public class MusicBeat {
static short[] samples = new short[2048];
Mpg123Decoder decoder;
AudioDevice device;
static FileHandle externalFile;
public boolean playing=true;
public MusicBeat(String name )
{
FileHandle file=Gdx.files.internal(name);
FileHandle external=Gdx.files.external("myappname/"+name);
if(!external.exists())file.copyTo(external); //copy the file to the external storage only if it doesnt exists yet
decoder = new Mpg123Decoder(external);
device = Gdx.audio.newAudioDevice(decoder.getRate(),decoder.getChannels() == 1 ? true : false);
playing=false;
externalFile=file;
}
void play()
{
playing=true;
Thread playbackThread = new Thread(new Runnable() {
#Override
public synchronized void run() {
int readSamples = 0;
while ( playing) {
if(decoder!=null){
if((readSamples = decoder.readSamples(samples, 0,samples.length))<=0){
decoder.dispose();
decoder = new Mpg123Decoder(externalFile);
playing=false;
}
device.writeSamples(samples, 0, readSamples);
}
}
}
});
playbackThread.setDaemon(true);
playbackThread.start();
}
public void stop(){
playing=false;
decoder.dispose();
}
public void setVolume(float vol){
device.setVolume(vol);
}
public void setSpeed(float speed){
device.setSpeed(speed);
}
}
Where to get the audio extension?(required for the AudioDevice)
The audio extension seems to have been deprecated and the jars cant be found easily, I have uploaded them here, its an old version but should work just fine.
Easier way?
If your game is only intent to run on desktop ,the Music class of libgdx on desktop relies again on OpenAL which gives as the power to play with the pitch ,so you just need to edit the Music interface(OpenALMusic on desktop) instead of the AudioDevice and get out the whole play sample by sample thing out of the equation,unfortunately as dawez said the Music class on android relies on MediaPlayer which is not giving us the pitch change option.
Conclusion :This method doesnt seem nice to me ,If your game really needs the pitch thing and it doesn't makes sense without it then go with it ,otherwise its just too much effort for such a small detail .
It seems that you cannot change the pitch of Music in Android.
To play music in libgdx you refer to the Interface Music:
public interface Music extends Disposable {
This is implemented by
package com.badlogic.gdx.backends.android;
public class AndroidMusic implements Music, MediaPlayer.OnCompletionListener {
private MediaPlayer player;
You are interested in the player object. That is of type MediaPlayer
package android.media;
public class MediaPlayer {
So now it boils down to the question if android is able to support pitching on the MediaPlayer class. Short answer no, long answer:Speed Control of MediaPlayer in Android
A workaround that you can do is to use a SoundPool even if that is slow, the loading can be started while the user is the loading screen. Otherwise you can try can split the music files in chunks and load them as you go still using a SoundPool. So you would do something like a lazy loading when the current part is coming to its end.
If you manage to find a suitable a solution, please post the relative code!
With the release of Android 6.0 (API level 23), "PlaybackParams" can be added to the MediaPlayer. These include playback speed and pitch among others.
I work with a MediaPlayer and set the state of the player often programmatically like for example:
if(mp.isPlaying()) {
mp.pause();
animationPausedMusic();
}
private void animationPausedMusic() {
// Changing button image to play button
btn_play.setBackgroundResource(R.drawable.play);
... // more code
}
But sometimes the logcat gives me the message:
"internal/external state mismatch corrected"
And then the play and pause function is not working anymore.
What does this message mean? And how can I solve it?
After going through the android's native framework for media player I found that in source file mediaplayer.cpp inside function bool MediaPlayer::isPlaying() The developer is checking if the currentState of media player is in STARTED state and yet the media player is not playing any media, so it tries to change the state to PAUSED state so that the state consistency should be maintained for API users.(and here is where he is printing the message "ALOGE("internal/external state mismatch corrected");")
Now If you go through the media player state diagram below:
You would notice that this may happen when the MediaPlayer moved to 'STARTED' state after a call to start() and at this time for some obscure reason has not yet started the playback and you fire a MediaPlayer.isPlaying() method call , The Framework treat this as state inconsistency and moves to 'PAUSED' state and that's why you cannot see anything playing further.
However, if someone has some better understanding please share your thoughts!
I ran into this recently, and like some other questions say, it's this bug (marked obsolete alas)
https://code.google.com/p/android/issues/detail?id=9732
I found this error occurs when playing a MIDI file, but only sometimes. It happens when mp.isPlaying() is called quickly after mp.start()
If you can manage to not call mp.isPlaying() for a little bit, the error doesn't occur. In my case, a 10th of a second or so made the difference between getting the error or not. It's awkward, but it works.
e.g.
//setting a new track
mp.setDataSource(path);
mp.prepare();
mp.start();
//calling mp.isPlaying() here or shortly after starts the problem
//since we know it's playing, we can store that state, or call
updateUiPlaying(); //eg instead of updateUi();
//or just call some code here that takes more time first
updateScaledImages(); //something that might take time
Log.v(TAG, "mp.isPlaying = " + mp.isPlaying()); //now isPlaying() shouldn't cause that error
Also, I put a check in when I pause later.
mp.pause()
if(mp.isPlaying()){
//shouldn't be playing, must be in error
mp.stop();
mp.release();
mp = new MediaPlayer();
//any other initialization here
}
Though the problem doesn't occur if there is a wait before calling isPlaying()
Apparently there is more than one cause of this message. The following solution worked for me. It may or may not work for you. I called the method MediaPlayer.reset() immediately after instantiating the MediaPlayer object:
MediaPlayer mp = new MediaPlayer();
mp.reset();
I just wanted the music in my activity to play endlessly (i.e. when my 38-second music ends, i wanted to play it again and again until the user leaves the page). By the way, i am using MediaPlayer.
ourSound = MediaPlayer.create(NewKFCActivity.this, R.raw.start);
ourSound.start();
Cheers!
You can call MediaPlayer#setLooping(boolean):
ourSound = MediaPlayer.create(NewKFCActivity.this, R.raw.start);
ourSound.setLooping(true);
ourSound.start();
The Google Voice Search comes with a significant delay from the moment you call it via startActivityForResult() until its dialog box is displayed, ready to take your speech.
This requires the user to always look at the screen, waiting for the dialog box to be displayed, before speaking.
So I was thinking of generating an audible signal instead of the dialog box by implementing RecognitionListener and sounding a DTMF tone in onReadyForSpeech() as in the following snippet:
#Override
public void onReadyForSpeech(Bundle params) {
Log.d(LCTAG, "Called when the endpointer is ready for the user to start speaking.");
mToneGenerator.startTone(ToneGenerator.TONE_DTMF_1);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Log.e(LCTAG, "InterruptedException while in Thread.sleep(50).");
e.printStackTrace();
} // SystemClock.sleep(50);
mToneGenerator.stopTone();
}
The tone sounds beautifully but... it is also "heard" by the microphone, arriving to the voice recognition service and always generating a recognition error ERROR_NO_MATCH.
Is there a way to work around this?
Here is a random idea, and it may very well not work.
Can you try disabling the microphone (maybe via AudioManager.setMicrophoneMute) while the tone is played?
Here's my code that's working for me, put into the onReadyForSpeech() callback of the RecognitionListener.
private void playSpeechReadyTone(){
audioManager.setMicrophoneMute(true);
MediaPlayer mediaPlayer = MediaPlayer.create(JarvisService.this, R.raw.doublebeep);
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer arg0) {
audioManager.setMicrophoneMute(false);
}
});
mediaPlayer.start();
}
I'm afraid that there isn't an easy&clean way to do that. As srf appointed, you shouldn't rely on AudioManager.setMicrophoneMute(boolean), so, AFAIK, the possibles are:
Play an audio file before call SpeechRecognizer.startListening(intent):
final MediaPlayer mediaPlayer = MediaPlayer.create(JarvisService.this, R.raw.doublebeep);
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer player) {
player.release();
// Safety start Speech Recognizer
mSpeechRecognizer.startListening(getSpeechRecognizerIntent());
}
});
mediaPlayer.start();
However, this solution has a problem... If may receive an RecognitionListener.onError(int error) before RecognitionListener.onReadyForSpeech being called and, in that case, you are still playing a beep sound every time (this will happen, for example, if you are not connected to the Internet and Speech Recognition is configured to work online)!
Besides, you should manage the case of cancelling the speech recognition process during audio (doublebeep) play.
Play the audio in the onReadyForSpeech callback (read original question) but use RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS with an appropriate value. In my case, my beep sound is really short (1 second max) and I set RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS to 4/5 seconds.
Also note that, as Google doc says:
Note also that certain values may cause undesired or unexpected results - use judiciously! Additionally, depending on the recognizer implementation, these values may have no effect.