Executing code after MediaPlayer is done playing? - java

I was wondering I'm working on an Android app where MediaPlayer/TextToSpeech is used to tell the user something and then a Speech Recognition object opens up after the MediaPlayer/TextToSpeech finishes and another is played after they answer the question with the recognition. Problem is I'm not 100% sure of a way, or good way, to delay the Speech Recognition from opening right after MediaPlayer is starts, or waiting till mediaplayer is done before speech recognition opens up. I see a few options based off my own knowledge/Google -
use the methods isPlaying(MediaPlayer)/isSpeaking(TextToSpeech) and putting them in some kind of loop to check until they aren't true anymore, then opening the speech recognition.
Call Thread.sleep(). The problem I see with this is I'm not sure exactly how long user is going to speak so it could still get interrupted unless I put it at a high time which just slows the app down.
I've research and played around with the Handler class a bit, but haven't fully comprehended how to do this...anyone help?

If you want to do something when a MediaPlayer finishes, you can set a OnCompletionListener with setOnCompletionListener() to receive a callback when the media playback is complete.

Related

Stop MediaPlayer 250ms from end of file

I'm using speech recognition in an interactive mobile app with google speech to text.
When the AI talks back to you, I stop listening to cancel out the noise.
Right now, I'm using onCompletedListener to resume recognition at the end of a file, but it would be ideal to start just before the file ends to account for network latency and optimize response time.
Is there a way to watch currentPosition and trigger an event 250ms from the end of each file? They are not uniform in length.
The only way to detect current position is by calling "MediaPlayer.getCurrentPosition()", so the only solution is to periodically check the position and check if "(MaxPosition - CurrentPosition)" is between 200-300ms. This means that you need to do this check each 50/75ms to be sure to remain in that range.
An improvement could be start to periodically check (as I explained above) ONLY after "MaxLength-250ms" from the beginning of "MediaPlayer.play()".
Obliviously if you allow Seeks in MediaPlayer, this timer should be changed according after each Seek.

Java Seamless Audio Transition/Loop

How can you ensure the transition between two pieces of audio is seamless?
In a JavaFX application, I am using the javafx.scene.media.MediaPlayer to play an intro-piece, which is proceeded by the main/looping-piece. The media is played just fine, but the issue is the transition and loop.
Here is what I am currently doing:
private static void foo(final Media intro, final Media loop) {
final MediaPlayer introPlayer = new MediaPlayer(intro);
introPlayer.play();
final MediaPlayer loopPlayer = new MediaPlayer(loop);
loopPlayer.pause(); // An attempt to load the media so it will be ready to be played.
introPlayer.setOnEndOfMedia(loopPlayer::play());
loopPlayer.setOnEndOfMedia(() -> loopPlayer.seek(Duration.ZERO));
//loopPlayer.setCycleCount(Integer.MAX_VALUE); // Similar to the above line, but there is still a delay between loops.
}
The MediaPlayer::pause does help some, but there is a very noticeable delay between the end of the intro media and the start of the looping media. Furthermore, there is another noticeable delay between the end of the looping media and the repeat.
I additionally tried using javafx.scene.media.AudioClip, since it supposedly has less overhead than a javafx.scene.media.MediaPlayer. I wrote my own listener to tell when the track ended (and to immediately thereafter start the looping piece), but I still saw a similar delay.
Here were some similar posts I found, but did not provide a solution to the problem:
JavaFX MediaPlayer playing background music loop with small intro music
This one is definitely relevant (coincidentally, it is almost the
anniversary of that post), but I am already using a .wav formatted
media file and still experience a delay.
JavaFX AudioClip.play()
Which is similar to what I tried with the Audioclip, exept I used a
scheduled executor to time when to replay the audio. (Where I still
experienced a delay).
And, as a final note, I have tested my audio in Audacity, where they transitioned and looped seamlessly.
What are some recommended solutions for these types of problems?
Edit:
Added an addendum to the code-block, mentioning MediaPlayer::setCycleCount(Integer)
I realize it's been a while since you posted. Have you found an answer? I am wondering if you loaded loopPlayer before playing introPlayer, if that would help.
If MediaPlayer's "listener" is just kind of sluggish, maybe switching to using Java's SourceDataLine with a LineListener used to trigger the looping cue would work more seamlessly? (I would use a Clip for the looping playback.)
Last suggestion, I have an audio library AudioCue that could work for this. The library includes an AudioCueListener that can trigger an event (such as starting another AudioCue playing) when a cue ends. But limitations of the library would require that you hold your music in memory, and that the source files be .wav's.
The AudioClip Javadocs state that an AudioClip represents a segment of audio that can be played with minimal latency and are usable immediately. However, it also states
Media objects are however better suited for long-playing sounds. This is primarily because AudioClip stores in memory the raw, uncompressed audio data for the entire sound, which can be quite large for long audio clips. A MediaPlayer will only have enough decompressed audio data pre-rolled in memory to play for a short amount of time so it is much more memory efficient for long clips, especially if they are compressed.
Depending on the length of the looping media, an AudioClip might be better suited for you. Instead of needing a ScheduledExecutorService to replay the audio, you can use AudioClip.setCycleCount(AudioClip.INDEFINITE) to loop forever.
Using this info, I believe your best bet is to use a MediaPlayer for the intro and then utilize MediaPlayer#setOnEndOfMedia to call the looping AudioClip; possibly having a small delay between the intro and looping transition but seamless after that.

Get the length of video recorded so far (or get accurate start time)

I want to synchronize other sensor data with the video I'm recording, and so I'd like to record "how far am I into the video" when the sensor is triggered. Is there any way to do this? I couldn't find an appropriate method on the MediaRecorder class.
Another solution would be to just get the precise start time of the video recording, but my tests show that the video starts ~1sec after calling mediarecorder.start, but it's not consistent.
You have raised an interesting topic.
If you refer to the documentation in the developer page, the following diagram states the recording is supposed to start when the start() method is called.
Your solution is supposed to be correct albeit there is a lag up to 1 sec. I would do it the same way
I went through the MediaRecorder class methods, the only method that seems to be useful is the callback setOnInfoListener().
Set it and see if you will get some kind of information when the recording starts! I haven't tried it yet though.

Android Programming: Looping Voice Recognition

I'm looking to make a custom Android app to help out a physically disabled person. I need to heavily rely on voice recognition. The idea would be:
the app (via voice recognition) accepts his speech
the app parses his speech and executes his commands ("email dad", "text fred", "what time is it?", etc, plus other things I'll be adding to control his tv, lights, etc)
after execution, the app waits for his next command (loop back to #1)
I have #1 & #2 working fine, but I can't figure out a good method for #3. I can't leave Google's voice recognition view running indefinitely because it could be hours before the next command. But the 'trigger' does have to be based on sound/voice. Has to be completely hands free.
Ideally, the app would just listen for a sound, and if that sound is above a certain pre-programmed decibel level, I'd start voice recognition. Is it possible to constantly loop just listening for a noise, then react if it's 'so' loud?
Any ideas?
Thanks
So the idea is that you want voice recognition to be ongoing. It is very hard to do that. But the way that I accomplished this is by using:
try {
Thread.sleep(4500);
mSpeechRecognizer.startListening(mSpeechRecognizerIntent);
} catch (InterruptedException e) {
// It depends on your app logic what to do with InterruptedException
// You can process it or rethrow or restore interrupted flag
}
After the onReady (so if the user doesn't say something around 4.5 seconds it resets and at results. This worked great for me.
CMUSphinx is a great solution for this:
You can easily listen continuously, a voice detection API is provided
You can increase accuracy for a custom set of commands
You can adapt the model to the user voice thus increasing accuracy significantly
For more details on using CMUSphinx on Android see
http://cmusphinx.sourceforge.net/2011/05/building-pocketsphinx-on-android/

Java stop MIDI playback

Hi I have java application which plays midi messages from sequence. I'm doing this using jfugue library.
the problem is when I'm tryingto stop playback with stop button (which call sequencer.stop() and sequencer.close()) the last played note is sound all of rest time, and I can't stop it.
So I'm asking about solution about stopping all audio and MIDI too! sound playback from java application.
Notice:
If you want propose just mute volume, you need to know that I want end-use will be able to press play button again and hear the sound again, so muting volumr will be not a solution, or explain please.
Thank you!
I'm guessing you need to call Player.allNotesOff() before calling sequencer.stop(). Untested, so please let me know if it didn't work.
When MIDI plays music, it uses a combination of NOTE_ON and NOTE_OFF events. It sounds like when you press the stop button, the sequence is stopping after a NOTE_ON event had been sent, but before a NOTE_OFF event was sent. That means the sound will continue to play indefinitely.
Player.allNotesOff() in JFugue makes a call to JavaSound's allNotesOff() method in the Channel class; this call is made for each MIDI Channel (there are 16 channels). It's unfortunate that this solution isn't working. Try calling Player.allNotesOff() after sequencer.stop(), see if that helps.

Categories